Rails 5 - has_many through和嵌套属性表单

时间:2017-06-07 14:50:28

标签: ruby-on-rails ruby forms has-many-through model-associations

我有两个模型请求 TableLocation ,两者都有 has_many到关系,由 RequestLocation 表连接。

我正在尝试创建一个嵌套表单,并且table_location数据没有保存到数据库中。

正如您所见, table_locations" => [" 1"] 参数正在传递给创建操作但未保存。

感谢任何帮助。

控制台输出

Started POST "/requests" for 127.0.0.1 at 2017-06-07 10:35:26 -0400
Processing by RequestsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"mHV/xbmdfHmCAsi16KXlW+0bWVSkEo9SRVchdyPpL60o3m3SuKEt4nuUT4PJNEyCsWq3Nj4IWiCMlDbhiPewdA==", "request"=>{"concierge_name"=>"Alex", "concierge_number"=>"954-123-4567", "concierge_email"=>"alex@email.com", "client_name"=>"Adam", "client_number"=>"954-765-4321", "client_email"=>"adam@email.com", "hotel_employee"=>"0", "concierge_service"=>"0", "vip_promoter"=>"0", "arriving_with_client"=>"1", "client_alone"=>"0", "males"=>"", "females"=>"1", "table_minimum"=>"1000", "arrival_time(1i)"=>"2017", "arrival_time(2i)"=>"6", "arrival_time(3i)"=>"7", "arrival_time(4i)"=>"14", "arrival_time(5i)"=>"35", "table_locations"=>["1"], "comments"=>""}, "commit"=>"Submit"}
   (0.1ms)  BEGIN
  SQL (0.4ms)  INSERT INTO "requests" ("concierge_name", "concierge_number", "concierge_email", "client_name", "client_number", "client_email", "arriving_with_client", "people", "females", "table_minimum", "arrival_time", "comments", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING "id"  [["concierge_name", "Alex"], ["concierge_number", "954-123-4567"], ["concierge_email", "alex@email.com"], ["client_name", "Adam"], ["client_number", "954-765-4321"], ["client_email", "adam@email.com"], ["arriving_with_client", "t"], ["people", 1], ["females", 1], ["table_minimum", 1000], ["arrival_time", "2017-06-07 14:35:00"], ["comments", ""], ["created_at", "2017-06-07 14:35:26.658718"], ["updated_at", "2017-06-07 14:35:26.658718"]]
   (0.3ms)  COMMIT
Redirected to http://localhost:3000/thanks
Completed 302 Found in 8ms (ActiveRecord: 0.8ms)

应用/模型/ request.rb

class Request < ApplicationRecord
    has_many :request_locations
    has_many :table_locations, through: :request_locations
end

应用/模型/ table_locations.rb

class TableLocation < ApplicationRecord
    has_many :request_locations
    has_many :requests, through: :request_locations
end

应用/模型/ request_location.rb

class RequestLocation < ApplicationRecord
    belongs_to :request
    belongs_to :table_location
end

应用/控制器/ requests_controller.rb

class RequestsController < ApplicationController
  before_action :set_request, only: [:show,
                                     :edit,
                                     :update,
                                     :destroy]

  before_action :authenticate_admin!, except: [:index,
                                               :new,
                                               :create]

  def index
    redirect_to root_path unless admin_signed_in?
    @requests = Request.search(params[:term], params[:filter], params[:page])
  end

  def show
  end

  def new
    @request = Request.new
  end

  def edit
  end

  def create
    @request = Request.new(request_params)
    @request.people = (@request.males || 0) + (@request.females || 0)

    respond_to do |format|
      if @request.save
        format.html { redirect_to thanks_path, notice: 'Request was successfully created.' }
        format.json { render :show, status: :created, location: @request }
      else
        format.html { render :new }
        format.json { render json: @request.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @request.update(request_params)
        format.html { redirect_to @request, notice: 'Request was successfully updated.' }
        format.json { render :show, status: :ok, location: @request }
      else
        format.html { render :edit }
        format.json { render json: @request.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @request.destroy
    respond_to do |format|
      format.html { redirect_to requests_url, notice: 'Request was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private

    def set_request
      @request = Request.find(params[:id])
    end

    def request_params
      params.require(:request).permit(:concierge_name,
                                      :concierge_number,
                                      :concierge_email,
                                      :client_name,
                                      :client_number,
                                      :client_email,
                                      :hotel_employee,
                                      :concierge_service,
                                      :vip_promoter,
                                      :arriving_with_client,
                                      :client_alone,
                                      :people,
                                      :males,
                                      :females,
                                      :table_minimum,
                                      :arrival_time,
                                      :comments,
                                      table_locations: [:id]
      )
    end
end

应用/视图/请求/ _form.html.erb

...
<% TableLocation.all.each do |t| %>
    <%= check_box_tag "request[table_locations][]", t.id, @request.table_locations.include?(t.id) %>
    <%= t.location %>
    <br />
<% end %>
...

1 个答案:

答案 0 :(得分:0)

说明:

  • 您的request_params允许table_locations: [:id],但这只允许以下格式:

    Parameters: {"utf8"=>"✓", ... "request"=>{"table_locations"=>{"id"=>"1"}, "comments"=>""}, "commit"=>"Submit"}
    

    但你的表现是:

    Parameters: {"utf8"=>"✓", ... "request"=>{"table_locations"=>["1"], "comments"=>""}, "commit"=>"Submit"}
    
    • 因此,请在create方法中尝试:puts request_params,然后您会注意到它没有table_locations值(即使您认为它存在,但它&# 39; s not),因为它不是'#34;正确&#34;在您的强大参数request_params中列入白名单。
  • 为了能够将多个TableLocations对象关联到新构建的Request对象,格式应如下所示

    request = Request.new(table_location_ids: [1,2,3,4,5])
    

    但是从你的实施中,你就是这样做的(这不会起作用):

    request = Request.new(table_locations: [1,2,3,4,5])
    # => this will raise an error:
    # ActiveRecord::AssociationTypeMismatch: TableLocation expected, got Fixnum
    # however yours didn't raise an error, because it was not whitelisted in the request_params in the first place
    

解决方案:

<强> requests_controller.rb

def request_params
  params.require(:request).permit(..., table_location_ids: [])
end

<强> _form.html.erb

<% TableLocation.all.each do |t| %>
  <%= check_box_tag "request[table_location_ids][]", t.id %>
  <%= t.location %>
  <br />
<% end %>

建议:

  • 如果您还不知道可以通过这种方式执行以下操作,我将重构您的代码,看起来像这样:

    <强> requests_controller.rb

    def create
      @table_locations = TableLocation.all
    end
    

    <强> _form.html.erb

    <%= form_for @request do |f| %>
      <% @table_locations.each do |table_location| %>
        <%= f.check_box :table_location_ids, multiple: true, table_location.id %>
      <% end %>
    <% end %>