【问题标题】:Retrieving data from nested form从嵌套表单中检索数据
【发布时间】:2019-03-07 09:51:25
【问题描述】:

我正在尝试重新创建类似于 app.stackoverflow 的堆栈溢出。一个用户提出问题,其他人可以回答。我在问题页面上有一个缩进的嵌套表单,以便从其他用户那里获得答案。

在发布答案后我很难检索数据,并且我在更新操作的问题控制器页面上错误地设置了@answer,我无法弄清楚如何正确检索此变量鉴于来自 questions_controller 的参数没有单独设置答案的详细信息。如何检索与@answer 相关的参数部分,以便我可以设置变量,或者我可能需要为此使用不同的路由? 我的表单如下所示:

 <%= form_for @question do |form| %>
   <%=form.fields_for :answer do |answer_form| %>
     <div class="form-group">
        <%=answer_form.text_area :answer_attributes, placeholder: "Add your answer", rows:10, class:"form-control" %>
<%=answer_form.hidden_field :user_id, value: current_user.id, class:'d-none' %>
         <%=answer_form.hidden_field :question_id, value: @question.id %>
      </div>
    <% end %>

    <div>
       <%=form.submit 'Post Your Answer', class: 'btn-primary' %>
   </div>
 <% end %>

我的问题模型如下所示:

 class Question < ApplicationRecord
  has_many :answers, dependent: :destroy
  belongs_to :user
  accepts_nested_attributes_for :answers
  validates :headline, presence: true , length: { minimum: 20 }
  validates :body, presence: true, length: { minimum: 50 }
  validates_associated :answers
end

答案模型是:

class Answer < ApplicationRecord
  belongs_to :user
  belongs_to :question
  validates :body, presence: true, length: { minimum: 50 }
end

问题控制器:

class QuestionsController < ApplicationController
  before_action :authenticate_user!, except: [:index, :show]
  before_action :set_question, except: [:index, :new, :create]

  def index
    @questions = Question.all.order("id DESC")
  end

  def show
    @question = Question.find(params[:id])
    @user = User.find(@question.user_id)
    @answers = @question.answers
    @answer = Answer.new
  end

  def new
    @question = Question.new
    @question.answers.new
  end

  def create
    @question = current_user.questions.new(question_params)
    if @question.save
      flash[:notice] = "You have successfully posted your question"
      redirect_to  @question

    else
      @errors = @question.errors.full_messages
      render action: :new
    end
  end

  def edit
    set_question
    @question = Question.find(params[:id]) 
  end

  def update
     @question = Question.find(params[:id])
     @question.update(question_params)
     @answer = @question.answers.new(question_params)
     @question.answers.first.user_id = current_user.id

   if @question.save
     flash[:notice] = "You have sucessfully posted your answer"
     redirect_to @question
   else
      redirect_to new_question_answer_path(@answer), flash: { danger: @question.errors.full_messages.join(",")}
    end
  end

  private

  def set_question
    @question = Question.find(params[:id])
  end

  def question_params
    params.require(:question).permit(:headline, :body, :user_id, :answer, answers_attributes:[:body, :user_id, :question_id])
  end
end

应答控制器:

class AnswersController < ApplicationController
  before_action :find_question

  def index
    @answers = @question.answers
    @user = User.find(@question.user_id)
  end

  def show
    @answer = Answer.find(params[:id])
    @user = User.find(@question.user_id)
  end

  def new
    @answer = Answer.new(:question_id => @question.id)
  end

  def create
    @answer = Answer.new(answer_params)


    if @answer.save
      flash[:notice] = "You have sucessfully created the answer."
      redirect_to(answers_path(@answer, :question_id => @question.id))
    else
      flash[:alert] = "Failed to save the answer."
      @errors = @answer.errors.full_messages
      render :new
    end
  end

  def edit
    @answer = Answer.find(params[:id])
  end

  def update
    @answer = Answer.find(params[:id])
    if @answer.update_attributes(answer_params)
      flash[:notice] = "You have sucessfully updated the answer."
      redirect_to(answer_path(@answer, :question_id => @question.id))
    else
      render :edit
    end
  end

  def delete
    @answer = Asnwer.find(params[:id])
  end

  def destroy
    @answer = Answer.find(params[:id])
    @answer.destroy
    flash[:notice] = "Answer was destroyed"
    redirect_to(answers_path)
  end

  private

   def answer_params
     params.require(:answer).permit(:body, :user_id, :question_id)
   end

   def find_question
     @question = Question.find(params[:question_id])
   end

end

我的路线文件如下所示:

    Rails.application.routes.draw do

  get 'questions/index'



  root to: 'questions#index'

  resources :questions  do
    resources :answers
  end

  devise_for :users
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

更新:这里是从服务器启动和显示索引页面到我进入问题页面并记录答案的那一刻的日志

   rails server
=> Booting Puma
=> Rails 5.2.2 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.0 (ruby 2.6.0-p0), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Started GET "/questions/11/answers" for 127.0.0.1 at 2019-03-07 16:10:13 +0600
   (1.4ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
  ↳ /Users/irina/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2/lib/active_record/log_subscriber.rb:98
Processing by AnswersController#index as HTML
  Parameters: {"question_id"=>"11"}
  Question Load (0.8ms)  SELECT  "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT $2  [["id", 11], ["LIMIT", 1]]
  ↳ app/controllers/answers_controller.rb:65
  User Load (2.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ app/controllers/answers_controller.rb:6
  Rendering answers/index.html.erb within layouts/application
  Answer Load (0.9ms)  SELECT "answers".* FROM "answers" WHERE "answers"."question_id" = $1  [["question_id", 11]]
  ↳ app/views/answers/index.html.erb:11
  User Load (1.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ app/views/answers/_new.html.erb:7
  Rendered answers/_new.html.erb (61.7ms)
  Rendered answers/index.html.erb within layouts/application (92.7ms)
[Webpacker] Compiling…
Started GET "/questions/11/answers" for 127.0.0.1 at 2019-03-07 16:10:18 +0600
Processing by AnswersController#index as HTML
  Parameters: {"question_id"=>"11"}
  Question Load (1.4ms)  SELECT  "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT $2  [["id", 11], ["LIMIT", 1]]
  ↳ app/controllers/answers_controller.rb:65
  User Load (1.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ app/controllers/answers_controller.rb:6
  Rendering answers/index.html.erb within layouts/application
  Answer Load (1.3ms)  SELECT "answers".* FROM "answers" WHERE "answers"."question_id" = $1  [["question_id", 11]]
  ↳ app/views/answers/index.html.erb:11
  User Load (1.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ app/views/answers/_new.html.erb:7
  Rendered answers/_new.html.erb (9.3ms)
  Rendered answers/index.html.erb within layouts/application (18.5ms)
Completed 200 OK in 133ms (Views: 108.3ms | ActiveRecord: 18.4ms)


[Webpacker] Compilation failed:

Hash: 53a953077891e4cef2e8
Version: webpack 3.12.0
Time: 2928ms
                                  Asset       Size  Chunks             Chunk Names
    application-c57a289721a93641de38.js     3.1 kB       0  [emitted]  application
application-c57a289721a93641de38.js.map    2.49 kB       0  [emitted]  application
                          manifest.json  142 bytes          [emitted]
   [0] ./app/javascript/packs/application.js 346 bytes {0} [built] [failed] [1 error]

ERROR in ./app/javascript/packs/application.js
Module build failed: SyntaxError: Unexpected token (14:15)

  12 |     if(window.railsEnv && window.railsEnv === 'development'){
  13 |       try {
> 14 |         render(<App />, reactElement)
     |                ^
  15 |       } catch (e) {
  16 |         render(<RedBox error={e} />, reactElement)
  17 |       }


Completed 200 OK in 11715ms (Views: 11626.9ms | ActiveRecord: 27.7ms)


Started PATCH "/questions/11" for 127.0.0.1 at 2019-03-07 16:10:41 +0600
Processing by QuestionsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"q7HQt4uGPwBIIz0icswfJLWMRk6MiopIfWu9JBcjkuX1VpGBdwlwZu903NDuebSaX8Y90VHnvcEoaV8unV2zkw==", "question"=>{"answer"=>{"answer_attributes"=>"This is the test answer to see how the information goes through", "user_id"=>"3", "question_id"=>"11"}}, "commit"=>"Post Your Answer", "id"=>"11"}
  User Load (0.8ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ /Users/irina/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2/lib/active_record/log_subscriber.rb:98
  Question Load (0.5ms)  SELECT  "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT $2  [["id", 11], ["LIMIT", 1]]
  ↳ app/controllers/questions_controller.rb:55
  CACHE Question Load (0.0ms)  SELECT  "questions".* FROM "questions" WHERE "questions"."id" = $1 LIMIT $2  [["id", 11], ["LIMIT", 1]]
  ↳ app/controllers/questions_controller.rb:39
Unpermitted parameter: :answer
   (0.5ms)  BEGIN
  ↳ app/controllers/questions_controller.rb:40
  User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ app/controllers/questions_controller.rb:40
  Answer Load (0.5ms)  SELECT "answers".* FROM "answers" WHERE "answers"."question_id" = $1  [["question_id", 11]]
  ↳ app/controllers/questions_controller.rb:40
   (0.3ms)  COMMIT
  ↳ app/controllers/questions_controller.rb:40
Unpermitted parameter: :answer
   (0.3ms)  BEGIN
  ↳ app/controllers/questions_controller.rb:44
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ app/controllers/questions_controller.rb:44
   (0.4ms)  ROLLBACK
  ↳ app/controllers/questions_controller.rb:44
Completed 500 Internal Server Error in 97ms (ActiveRecord: 8.3ms)



ActionController::UrlGenerationError (No route matches {:action=>"new", :controller=>"answers", :question_id=>nil}, missing required keys: [:question_id]):

app/controllers/questions_controller.rb:48:in `update'

UPDATE NO 2。看起来由于这个错误设置了@answer,@question 没有按预期保存,并且条件踢的第二部分重定向到 new_question_answer_path。我尝试将其更新为 edit_question_answer_path 并且它给出了与没有路由匹配的相同错误。

如果我在 Pry 中打开答案,我会得到以下对象:

[1] pry(#<QuestionsController>)> @answer
=> #<Answer:0x00007fc3ec823c98
 id: nil,
 body: nil,
 question_id: 11,
 user_id: 3,
 selected: nil,
 created_at: nil,
 updated_at: nil>

更新 3 看起来像将我的 routes.rb 更改为

 Rails.application.routes.draw do
  resources :questions, :has_many => :answers
  root to: 'questions#index'
  resources :questions  do
      resources :answers
    end
  devise_for :users
end

并更改此答案的形式

<h2> Your Answer </h2>


<%= form_for [@question, Answer.new] do |form| %>

     <div class="form-group">
        <%=form.text_area :body, placeholder: "Add your answer", rows:10, class:"form-control" %><br>

         <%=form.hidden_field :user_id, value: current_user.id, class:'d-none' %>
         <%=form.hidden_field :question_id, value: @question.id %>
      </div>

    <div>
       <%=form.submit 'Post Your Answer', class: 'btn-primary' %>
   </div>
<% end %>

成功了并帮助解决了问题。我不确定这是否是一个完美的解决方案)

【问题讨论】:

  • 我们需要查看您的服务器日志以了解参数是如何传递的。点击提交后复制并粘贴服务器输出的任何内容
  • 奇怪的是,您为问题构建了一个表单,而您只查询答案。为什么不只为先前存在的问题下方的答案构建一个表单。因为您已经将问题 ID 作为隐藏字段传递,所以您可以轻松地将答案与正确的问题相关联...... 一件小事:您将 Answer 设为 User 的子项,但您不需要将其作为答案已经是问题的孩子,它本身就是用户的孩子。您可以轻松找到给出任何答案的用户。
  • 看起来像更新 route.rb 和编辑表单就可以了,并且应用程序正常工作。我以更新 NO 3 的形式将新的 route.rb 和 view/answers/_new.html.erb 添加到我的问题中。
  • 这个视频看起来很有帮助railscasts.com/episodes/…
  • Maxence,感谢您让我朝着正确的方向思考我认为表格设置不正确。同时,该应用程序的结构期望有一个用户提出问题,而任何其他用户回答它,所以我看不出我将如何追溯用户 ID 以获得问题的答案。我没有在我的问题中澄清这一点是我的错。

标签: ruby-on-rails forms nested


【解决方案1】:

好像把我的 routes.rb 改成

  Rails.application.routes.draw do
      resources :questions, :has_many => :answers
      root to: 'questions#index'
      resources :questions  do
          resources :answers
      end
      devise_for :users
   end

并更改此答案的形式

 <%= form_for [@question, Answer.new] do |form| %>
     <div class="form-group">
         <%=form.text_area :body, placeholder: "Add your answer", rows:10, 
         class:"form-control" %><br>
         <%=form.hidden_field :user_id, value: current_user.id, class:'d-none' %>
         <%=form.hidden_field :question_id, value: @question.id %>
      </div>
      <div>
          <%=form.submit 'Post Your Answer', class: 'btn-primary' %>
      </div>
 <% end %>

成功了并帮助解决了问题。我不确定这是否是一个完美的解决方案)

【讨论】:

    猜你喜欢
    • 2018-12-15
    • 2022-01-18
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 2017-12-22
    • 2017-06-09
    • 2022-01-07
    相关资源
    最近更新 更多