问题
I have the following setup.
1 product has many product_types. many product_types have 1 type. A HABTM relationship from my understanding of the docs.
My models are
class Product < ApplicationRecord
has_and_belongs_to_many :types
end
class Type < ApplicationRecord
has_and_belongs_to_many :products
end
I have a join table migration as such
class CreateJoinTableProductTypes < ActiveRecord::Migration[5.1]
def change
create_join_table :products, :types do |t|
t.index :product_id
t.index :type_id
end
end
end
I have created a form - hopefully created correctly where now I have the following parameters being sent on form submit:
"product"=>{"name"=>"Product A", "description"=>"A cool product", "image_dir_path"=>"./",
"type"=>{"id"=>"1"}},"commit"=>"Create Product"}
I'm wondering 1) what is the best/rails convention for submitting the parameters for creating the product in the form and controller?
and
2) how are/do I get, the records inserted into the join table?
I have the following method for getting the params
def product_params
params.require(:product).permit(:name, :description, :image_dir_path, :type,)
end
but even then I can see in the logs unpermitted parameter for :type
at the moment my controller only has:
@product = Product.new(product_params)
I would greatly appreciate any advice on the rails way of creating this object. I've read the api docs for HABTM but don't see anything when it comes to the model object or how I should be handling this stuff in the controller.
Thanks!
回答1:
ActieRecord generates _ids
setters and getters for all has_many and has_and_belongs_to_many associations.
# creates 3 rows in products_types if they do not exist
# also deletes any rows not in the array
@product.update(type_ids: [1,2,3])
These are used together with the form options helpers to assign associations:
<%= form_for(@product) do |f| %>
<div class="field">
<%= f.label :type_ids %>
<%= f.collection_select :type_ids, Type.all, :id, :name, multiple: true %>
</div>
...
<% end %>
To whitelist the param you pass it as a option with the value []
which permits an array containing any scalar type.
def product_params
params.require(:product).permit(:name, :description, :image_dir_path, type_ids: [])
end
2) how are/do I get, the records inserted into the join table?
With the has_and_belongs_to_many
association you can only insert/access rows indirectly.
For example by:
@product.types
# or
@product.types << Type.first
# or
@product.types.create(name: 'Foo')
Or by using the type_ids
setter/getter previously mentioned. This is a key difference from has_many through:
where you have a join model that can be queried or created directly.
回答2:
After max's comment I realised Type relationship wasn't a HABTM but was a one to many with product. I had another model Size that was in a HABTM with Product though.
My Models look like this:
class Product < ApplicationRecord
belongs_to :product_type
has_and_belongs_to_many :sizes
end
class Size < ApplicationRecord
has_and_belongs_to_many :products
end
Join table is:
class CreateJoinTableProductSize < ActiveRecord::Migration[5.1]
def change
create_join_table :cakes, :sizes do |t|
t.index [:product_id, :size_id]
end
end
end
Size table is default Product table is
class CreateProducts < ActiveRecord::Migration[5.1]
def change
create_table :products do |t|
t.string :name
t.string :description
t.references :product_type, foreign_key: true
t.timestamps
end
end
end
My controller is the default - I just have the following params whitelisted
def cake_params params.require(:product).permit(:name, :description, :product_type_id, {:size_ids=>[]}) end
My _form has the following
<div class="field">
<%= form.label :product_type_id %>
<%= form.collection_select(:product_type_id, ProductType.all, :id, :name) %>
</div>
<div class="field">
<%= form.label :product_size %>
<%= collection_check_boxes(:product, :size_ids, Size.all, :id, :name) %>
</div>
Now I can submit the form, edit it and all values are displayed correctly!
来源:https://stackoverflow.com/questions/49847418/rails-habtm-setup-model-object-join-table-insertion-controller-setup