Rails nested form for complex associations - ruby-on-rails

Problems:
=rfv.text_area :value render void textarea in edit action (but in db this field has value)
can't get array of role_field_values[] in params
My models and associations:
class Participant < ActiveRecord::Base
belongs_to :role
has_many :role_field_values, dependent: :destroy
accepts_nested_attributes_for :role_field_values
end
class Role < ActiveRecord::Base
has_many :role_fields
has_one :participant
end
class RoleField < ActiveRecord::Base
belongs_to :role
has_many :role_field_values
end
class RoleFieldValue < ActiveRecord::Base
belongs_to :participant
belongs_to :role_field
end
My form edit.slim:
=simple_form_for [#project.becomes(Project), #participant] do |f|
=f.error_notification
h4 =#participant.profile.fio
.form-inline
=f.association :role, remote: true
=f.input :status
#role-fields
=fields_for :role_fields_values do |rfv|
-#participant.role.role_fields.each do |role_field|
.form-group
=rfv.hidden_field :role_field_id, value: role_field.id
br
=rfv.label role_field.name
=rfv.text_area :value, class: 'form-control'
.form-actions
= f.button :submit

Use f.fields_for instead of fields_for

Related

Rails 4.2.4 - dynamic menus in simple form with associations

I want to populate one selection field based on choice from other selected field. It's about categories / subcategories, when user is trying to submit new product. User picks main category in field 1, after picked main category he gets option to pick from field 2 children subcategories of picked main category from field 1. It's based on associations so it makes it harder for me.
Product model:
class Product < ActiveRecord::Base
belongs_to :user
has_many :categorizations
has_many :categories, through: :categorizations
end
Category model:
class Category < ActiveRecord::Base
belongs_to :parent, class_name: "Category"
has_many :children, class_name: "Category", foreign_key: "parent_id"
has_many :categorizations
has_many :products, through: :categorizations
end
Categorization model:
class Categorization < ActiveRecord::Base
belongs_to :product
belongs_to :category
end
new.html.erb
<%= simple_form_for #product, :html => { multipart: true } do |f| %>
<%= f.association :categories, collection: Category.where(parent_id: nil), prompt: 'Choose category' %>
<%= f.association :categories, collection: Category.where.not(parent_id: nil), prompt: 'Choose subcategory' %>
<%= f.button :submit, "Submit product" %>
<% end %>
UPDATE:
class ProductsController < ApplicationController
def update_categories
#categories = Category.where("parent_id = ?", params[:category_id])
respond_to do |format|
format.js
end
end
end
some routes:
get 'products/update_categories', as: 'update_categories'

Rails: Use a collection of checkboxes to add/remove entries on a different table with ActiveRecord

I have three objects: Contact, Sector, and Contact_sector.
Contact contains an id and some other irrelevant (non-reference) columns
Sector contains an id and sector column with ~10 editable entries
Contact_sector has a contact_id reference and a sector_id reference. In my mind I imagine that every sector that applies to some contact can be found here, and if a sector is un-applied it is removed from here.
I want to have a collection of checkboxes in the contact _form formed from list of entries in :sectors, but updating the form with certain boxes ticked adds/removes entries from :contact_sectors.
Where am I going wrong?
UPDATED: Fixed strong_params to permit sectors, now I am unable to find the sectors by id ActiveRecord::RecordNotFound (Couldn't find Sector with ID=["1", ""] for Contact with ID=1)
Models:
class Contact < ActiveRecord::Base
has_many :contact_sectors
has_many :sectors, through: :contact_sectors
accepts_nested_attributes_for :contact_sectors, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :sectors, :reject_if => :all_blank, :allow_destroy => true
end
class Sector < ActiveRecord::Base
has_many :contact_sectors
has_many :contacts, through: :contact_sectors
def name_with_initial
"#{sector}"
end
end
class ContactSector < ActiveRecord::Base
belongs_to :contact
belongs_to :sector
end
View:
<%= f.fields_for(:sectors) do |s| %>
<%= s.collection_check_boxes :id, Sector.all,
:id, :name_with_initial,
{ prompt: true }, { class: 'form-control' } %>
<% end %>
Controller
def edit
#contact.sectors.build
end
def contact_params
#Not sure if I need something like this or not
params['contact']['sectors'] = params['contact']['sectors']['id'].split(',')
params.require(:contact).permit(:firstname, :lastname,
contact_sectors_attributes: [:id],
sectors_attributes: [:_destroy, {:id => []}])
end
Instead of creating the join model explicitly you can just declare the relationship as has_many through: and let ActiveRecord handle the join model:
class Contact < ActiveRecord::Base
has_many :contact_sectors
has_many :sectors, through: :contact_sectors
accepts_nested_attributes_for :sector,
reject_if: :all_blank, allow_destroy: true
end
class Sector < ActiveRecord::Base
has_many :contact_sectors
has_many :contacts, through: :contact_sectors
end
class ContactSector < ActiveRecord::Base
belongs_to :contact
belongs_to :sector
end
<%= form_for(#contact) do |f| %>
<%= f.fields_for(:sectors) do |s| %>
<%= s.collection_check_boxes :id, Sector.all,
:id, :name_with_initial,
{ prompt: true }, { class: 'form-control' } %>
<% end %>
<% end %>
models
class Contact < ActiveRecord::Base
has_many :sectors, through: :contact_sectors
has_many :contact_sectors
accepts_nested_attributes_for :sectors
end
class Sector < ActiveRecord::Base
has_many :contacts, :through => :contact_sectors
has_many :contact_sectors
end
class ContactSector < ActiveRecord::Base
belongs_to :contact
belongs_to :sector
end
view
<%= form_for(#contact) do |f| %>
<% Sector.all.each do |sector| %>
<%= check_box_tag "contact[sector_ids][]", sector.id, f.object.sectors.include?(sector) %>
<%= sector.sector %>
<% end %>
<% end %>
controller
def update
#To make sure it updates when no boxes are ticked
#contact.attributes = {'sector_ids' => []}.merge(params[:contact] || {})
end
def contact_params
params.require(:contact).permit(:firstname, :lastname, sector_ids: [])
end
Recommended reading:
http://millarian.com/rails/quick-tip-has_many-through-checkboxes/
Rails 4 Form: has_many through: checkboxes

Form helpers for nested attributes has_many through in rails 4

I have 3 models with has_many through association:
class Spot < ActiveRecord::Base
has_many :seasons
has_many :sports, through: :seasons
accepts_nested_attributes_for :sports, :seasons
end
class Sport < ActiveRecord::Base
has_many :seasons
has_many :spots, through: :seasons
end
class Season < ActiveRecord::Base
belongs_to :spot
belongs_to :sport
end
I want to create a form so that editing the Spot you can create/edit Season for particular Sport.
I've got it working this way:
= form_for([#country, #spot], :html => { :multipart => true }) do |f|
#some Rails code here
= f.fields_for :seasons do |builder|
= builder.select :sport_id, options_from_collection_for_select(Sport.all, :id, :name, :sport_id)
= builder.text_field :months
= builder.hidden_field :spot_id
However it doesn't mark any Sport as "selected". I don't know what to substiture ":sport_id" for in the options.
I've got it working properly without Rails form helpers, but it seems that could be done with helpers:
- #spot.seasons.each do |season|
= select_tag "spot[seasons_attributes][][sport_id]", options_from_collection_for_select(Sport.all, :id, :name, season.sport.id)
= hidden_field_tag 'spot[seasons_attributes][][id]', season.id
= text_field_tag 'spot[seasons_attributes][][months]', season.months
Thanks in advance,
Vadim
Use collection_select helper on a form builder.
builder.collection_select(:sport_id, Sport.all, :id, :name)

rails list all items for a many to many including design

So I have the following models:
Image:
class Image < ActiveRecord::Base
has_many :product_images
has_many :products, :through => :product_images
attr_accessible :asset, :name, :description, :product_ids, :file_content_type, :is_boolean
accepts_nested_attributes_for :product_images
has_attached_file :asset
end
ProductImage:
class ProductImage < ActiveRecord::Base
belongs_to :product
belongs_to :image
attr_accessible :is_thumbnail
end
and Product:
class Product < ActiveRecord::Base
has_many :images, :through => :product_images
has_many :product_images
attr_accessible :name, :description, :thumbnail, :searchTerms, :group_ids, :upload_file_ids
end
Now what I would like to do on the images form is display a checkbox for all the products and then another checkbox for the is_thumbnail attribute
I have had a look into using simple_fields_for but this will only display if the product has already been added. Is there a way to do this?
<%= f.simple_fields_for(:product_images) do |builder| %>
<%= builder.input :is_thumbnail %>
<%= builder.association :products, include_blank: false %>
<% end %>
I'm not very familiar with simple_fields however building form inputs base on an instance will only allow you to "represent" that instance.
This means that you could print all already associated products using
builder.association :products
but if you want to print all products in your database you will need to fetch them, loop and display them in your form.

Rails 3 has_many :through Form

Can't figure out why this is not working. First time using :has_many => :through
Keep getting uninitialized constant User::Employmentship
class User < ActiveRecord::Base
has_many :employmentships
has_many :companies, :through => :employmentships
accepts_nested_attributes_for :employmentships, :allow_destroy => true, :reject_if => proc { |obj| obj.blank? }
attr_accessible :email, :password, :password_confirmation, :firstname, :lastname, :username, :role, :company_ids
end
class Company < ActiveRecord::Base
has_many :employmentships
has_many :users, :through => :employmentships
end
/views/users/_form.html.erb
<p>
<%= for company in Company.all do %>
<%= check_box_tag "user[company_ids][]", company.id, #user.companies.include?(company) %>
<%= company.name%>
<% end %>
</p>
EDIT - If I change #user.companies.include?(company) to false i get the form, but nothing updates.
EDIT 2 -
class Employmentship < ActiveRecord::Base
belongs_to :company
belongs_to :user
attr_accessor :company_id, :user_id
end
Where is you employmentship model? has_many_through is for going through another model.

Resources