New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Railsで質問・回答アプリを作ってください(実装編)の課題提出 #1
Conversation
def destroy | ||
@question.destroy | ||
redirect_to questions_url, notice: "質問「#{@question.title}」を削除しました。" | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここも同じく、current_userで絞り込みましょう!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
上記と同じです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
上記と同じ間違いです 🙇♂️ 🙇♂️ 🙇♂️
すみません!!!
app/controllers/users_controller.rb
Outdated
def edit | ||
@user = User.find(params[:id]) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current_userで絞り込んであげたほうがよさそうです!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
以下に書き換えました。
before_action :set_user, only: %i[show edit update destroy]
private
def set_user
@user = current_user
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GOOD!!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ちなみに、自分で指摘をしておきながら、何か違和感がある感じがしなくもないので、違ったらすみません!
app/controllers/users_controller.rb
Outdated
end | ||
|
||
def update | ||
@user = User.find(params[:id]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current_userで絞り込んであげたほうがよさそうです!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
上記と同じです。
app/controllers/users_controller.rb
Outdated
end | ||
|
||
def destroy | ||
@user = User.find(params[:id]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current_userで絞り込んであげたほうがよさそうです!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
上記と同じです。
class Question < ApplicationRecord | ||
validates :title, presence: true, length: { maximum: 30 } | ||
validates :content, presence: true | ||
before_validation :set_titleless_title |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
おお、before_validation、いいですね!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
今回は参考書通りですが、他でも意識できるようにしたいです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before_validation初めて聞きました。勉強させていただきます。
def set_titleless_title | ||
self.title = 'タイトルなし' if title.blank? | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
こういう親切設計、いいと思います!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
上記と同じです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あまり意識していなかったので見習います!
@@ -0,0 +1,14 @@ | |||
class Question < ApplicationRecord | |||
validates :title, presence: true, length: { maximum: 30 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここだけじゃないですが、validationをきちんと考える姿勢、いいですね!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(参考書通りですが)ありがとうございます!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
参考書を参考にするの、大事!!!
app/views/questions/search.html.slim
Outdated
table.table.table-hover | ||
thread.thread-default | ||
tr | ||
th= User.human_attribute_name('投稿者') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
単純に'投稿者'
としてもよい気がしますが、ymlファイルの方で後ほど定義するのを視野に入れているのであれば、一旦この形でもいいかと思います!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほど、リリースする段階ではきちんと変数で定義したほうがいいのですね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
と言いますか、
Question.human_attribute_name(:title)
こういう書き方するなら、意図がすごくよく分かるんですけれども、
User.human_attribute_name('投稿者')
こうやって書いている場合、普通に'投稿者'と書けるのに、なぜあえてこうしているんだろうと気になるという感じですね。
config/locales/ja.yml
で定義をするか、それか'投稿者’を直書きにするかのどちらかがいいと思います!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
config/locales/ja.yml
に定義して統一します。
.container | ||
.row | ||
p.text-left | ||
= auto_link(simple_format(h(@question.content), {}, sanitize: false, wrapper_tag: "div")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto_link、初めて知りました!
似たようなgemとして、rinkuというのもあるみたいですね!
https://github.com/vmg/rinku
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ご紹介してくださりありがとうございます。
調べて活用してみたいと思います。
@@ -35,6 +35,9 @@ | |||
|
|||
config.action_mailer.perform_caching = false | |||
|
|||
config.action_mailer.default_url_options = { host: 'localhost:3000' } | |||
config.action_mailer.delivery_method = :letter_opener_web |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
おお、lettter_opener_web、いいですね!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
簡単にメールを確認できますよね。
get 'search' | ||
end | ||
end | ||
post '/questions/:id/answers', to: 'answers#create' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
勘違いかもしれないですが、ここと重複してそうです!
resources :questions do
resources :answers, only: %i[create]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
申し訳ございません。消し忘れです。
気をつけます。
db/schema.rb
Outdated
create_table "answers", force: :cascade do |t| | ||
t.integer "question_id", null: false | ||
t.integer "user_id", null: false | ||
t.text "content", null: false | ||
t.datetime "created_at", null: false | ||
t.datetime "updated_at", null: false | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
外部キーにindexを貼ってあげると、検索が早くなるかと思います!
(データ量が少ないと、体感変わらないですが)
この記事がベストか微妙ですが、少し調べてみてください!
DBのインデックスと複合インデックス - Qiita
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
存在は知っていましてが、理解が足りなかったので実装しませんでした。
ご紹介してくださりありがとうございます。
db/schema.rb
Outdated
|
||
create_table "questions", force: :cascade do |t| | ||
t.string "title", limit: 30, null: false | ||
t.text "content" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
textにlimitをかけてあげてもいいかもしれないです!
(titleよりも、contentの方がより多くの文字数を入れ込まれる可能性があり、DBを圧迫されるかもしれないので)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DBについても配慮が必要ですね。
気をつけます。
db:rollbackして追記した場合、schema.rbに
t.text "content", limit: 500, null: false
が反映されましたが、
rails g migration ChangeQuestionsContentLimit500
をした場合、schema.rbに
ActiveRecord::Schema.define(version: 2021_12_24_215427) do
にしか違いが反映されませんでした。
どちらも違いないと思っていたのですが、前者のほうが適切ですか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
db:rollbackして追記した場合、schema.rbに
t.text "content", limit: 500, null: false
が反映されましたが、
rails g migration ChangeQuestionsContentLimit500
をした場合、schema.rbに
ActiveRecord::Schema.define(version: 2021_12_24_215427) do
にしか違いが反映されませんでした。
migrationファイルの中身を見ないと、何とも言えないですね!
どういった中身でした?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
db:rollbackして追記した場合
20211209100927_create_questions.rb
に下記を追記
class CreateQuestions < ActiveRecord::Migration[5.2]
def change
create_table :questions do |t|
t.string :title, limit: 30, null: false
t.text :content, limit: 500, null: false
t.boolean :solved_check, default: false, null: false
t.timestamps
end
end
end
create_table "questions", force: :cascade do |t|
t.string "title", limit: 30, null: false
t.text "content", limit: 500, null: false
t.boolean "solved_check", default: false, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id", null: false
t.boolean "admin", default: false, null: false
t.index ["user_id"], name: "index_questions_on_user_id"
end
rails g migration ChangeQuestionsContentLimit500をした場合
マイグレーションファイルに下記を作成
class ChangeQuestionsContentLimit500 < ActiveRecord::Migration[5.2]
def change
def up
change_column :questions, :content, :text, limit: 500
end
def down
change_column :questions, :content, :text
end
end
end
schema.rb
ActiveRecord::Schema.define(version: 2021_12_29_205612) do
.
.
create_table "questions", force: :cascade do |t|
t.string "title", limit: 30, null: false
t.text "content"
t.boolean "solved_check", default: false, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id", null: false
t.boolean "admin", default: false, null: false
t.index ["user_id"], name: "index_questions_on_user_id"
.
.
User.create!( | ||
name: '管理者', | ||
nickname: 'マネージャー', | ||
email: 'manager@example.com', | ||
password: 'password', | ||
password_confirmation: 'password', | ||
admin: true | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
こんな感じでシードデータまで用意したのはポイント高いですね!
Shunさん以外、たぶんほぼいないんじゃないかと思います!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ユーザーや質問があった場合のレイアウトを見てみたかったので使いました。
|
||
def destroy | ||
@question.destroy | ||
redirect_to questions_url, notice: "質問「#{@question.title}」を削除しました。" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
勘違いだったらすいません、、、削除が終わったら/admin/questions
ではなく/questions
にリダイレクトされるということでよろしいでしょうか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ご指摘の通り私のミスです。
正しくはadmin_questions_path
に書き直しました。
ありがとうございます。
@@ -0,0 +1,27 @@ | |||
class Admin::QuestionsController < ApplicationController | |||
before_action :required_admin | |||
before_action :set_q, only: %i[index search] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
変数宣言の共通化できていてすごいです!自分はできていなかったので見習います、、、
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
おお、レビューありがとうございます。
DRY大切ですよね!実装し忘れてしまうことも多いですが、、
|
||
def required_admin | ||
redirect_to root_path unless current_user.admin? | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app/controllers/admin/questions_controller.rb
にもrequired_admin
メソッドが定義されていたと思います。
2箇所に全く同じメソッドが定義されているので共通化した方が良いと思うのですが、ベースコントローラーに定義すると1箇所だけに定義するだけで済むと思います!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ご指摘ありがとうございます。おっしゃる通りです。
共通化いたします。
|
||
def create | ||
@question = Question.find(params[:question_id]) | ||
@answer = @question.answers.build(user_id: current_user.id, content: params[:answer][:content]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
せっかく書いたanswer_params
メソッドがどこにも使われていないように見受けられます!
もし使うのであれば(というかストロングパラメータなので使った方が良いと思います)、こういう書き方でもいいかもしれません!
mergeを使う書き方は賛否両論あるかもしれませんがご了承ください、、、
@answer = @question.answers.build(answer_params.merge(user_id: current_user.id))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ストロングパラメータは確かに必要ですね!
実装いたします。
end | ||
|
||
def update | ||
@question.update!(question_params) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update!
だと何かエラーが起きたときに例外が発生するので、バリデーションのエラーなどが返ってこないと思います!(自分も指摘されたことがあります、、、)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
例外処理という言葉きくとドキッとしますが、目を背けず勉強したいと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
例外処理という言葉きくとドキッとします
エラー画面が嫌いってことなんですかね?笑
app/mailers/sample_mailer.rb
Outdated
@user_from = params[:user_from] | ||
@user_to = params[:user_to] | ||
@question = params[:question] | ||
mail(to: "#{@user_to}.email", subject: "#{@user_from}さんが質問を投稿しました。") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
こちらの↓「クォーテーションを付けないとメール送信ができなかった件」なのですが、
https://github.com/keit1722/q_and_a_app/pull/1/files#r775154806
もう一度メール部分のコードを読ませていただきました!
@user_to
には送信先のユーザー全員情報が配列で入っていように思えます。
その場合、送信先(to:
)に配列が指定されているので上手く送信できなかったのではないかと推測しています!
ちなみに、宛先に指定したユーザー全員に送信できていますか?
宛先ユーザーの配列をループして一人ひとりのemail宛に送信すれば上手くいくのではないかと思いました!(クォーテーションがなくても送信できるかも?)
間違っていたらすいません、、、
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keitさんの仮説が正しそう。
2パターンやりようがありますね。
一つ目
ユーザーの数分send_when_question
を呼ぶ。
receivers.each do |user|
SampleMailer.with(user_from: current_user,
user_to: user,
question: @question).send_when_question.deliver_now
end
二つ目
toにはメールアドレスの配列を渡すこともできるのでそれを活用する
mail(to: @user_to.map { |user| user.email } ", subject: "#{@user_from}さんが質問を投稿しました。")
ですが二つ目は基本やっちゃダメですね。
理由としてはメールの宛先が他の人にもバレるので。
例えばAさんとBさんにメールを送ったとして、Aさんの受信メールを見るとTo(宛先)にBさんも含まれていることがわかってしまう。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ご指摘ありがとうございます。
eachメソッドで一人ひとりに送るという方法も考えたのですが、別で実装したいと思ったのでこの形になりました。確認してみましたが、一人にしかメール通知できていなかったので実装を変えたほうがいいかもしれません。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
一人にしかメール通知できていなかった
これも宛先のアドレスが不正なので送られないはず(letter_openerでは宛先がなんであれ送られてるように見えるけど)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
コメントしましたのでよろしくお願いします!
def set_titleless_title | ||
self.title = 'タイトルなし' if title.blank? | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あまり意識していなかったので見習います!
t.datetime "created_at", null: false | ||
t.datetime "updated_at", null: false | ||
t.integer "user_id", null: false | ||
t.boolean "admin", default: false, null: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
理解できてなくてすみません。
Questionsにはどうしてadminカラムを設けるんですか?
ざっとみた感じ、使っていないような気がしました。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
すみません、自分でもなぜ設定したのかわかりませんでした。
参考書に従って設定したのかもしれませんが削除します。
ご指摘ありがとうございます!
body.text-center | ||
.navbar.navbar-expand-md.navbar-light.bg-light | ||
.container-fluid | ||
.navbar-brand= link_to(image_tag('/logo.png', size:'75x50'), root_url) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
オリジナルのロゴ使うの良いですね!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ネットのフリー素材から拝借してきたものです。
t.string "email", null: false | ||
t.string "password_digest", null: false | ||
t.string "nickname" | ||
t.string "picture" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
自信がないのですが。。。(違ったらごめんなさい)
Active Strageを使って画像をUserに紐付ける場合、カラムを設ける必要はありましたっけ?
カラムを設定する、という記事も見かけましたが
実際のところは必要ないんじゃないかと思います。(記事が誤っているか古い?)
Railsガイドでも触れていないような気がします。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ご指摘ありがとうございます!
確かにUsersテーブルにカラムを設ける記載が見当たりませんね!
実際にカラムを削除してアバター画像が登録できるが試しました。
class RemovePictureFromUsers < ActiveRecord::Migration[5.2]
def up
remove_column :users, :picture
end
def down
add_column :users, :picture, :string
end
end
このマイグレーションファイルを実行してカラムを削除し、アバター画像が登録できました。
やはり画像用のカラムは必要ありませんでした。
非常に勉強になりました!!
質問回答アプリの実装をしました。
コードレビューお願い致します。
苦労したこと
疑問点
app/controllers/questions_controller.rb
のindexメソッド内の条件分岐で、真偽値であるtrue・false
をシングルクォーテーションで囲まなければならないのか?できなかったこと
app/views/questions/index.html.slim
で解決・未解決のタブボタンをbootstrapのサンプル通りに実装できなかった。Checkbox and radio button groups
app/views/questions/show.html.slim
で質問内容のテキストを左寄せにできなかった。app/views/questions/show.html.slim
で、回答内容が空だったときにエラーメッセージが表示されないこと。工夫したところ