I am not sure why my checkboxes for a has_many through are not saving. This is a rather complex form (An online application for a language summer program) so in addition to regular applicant information, I am collecting attributes of a LanguageBackgroundAndInterest model using a fields_for. Part of these attributes are the books that the applicant used to learn the language. The code looks like this:
<%= f.fields_for :language_background_and_interest do |builder| %>
<div class="field">
<%= hidden_field_tag "language_background_and_interest[book_ids][]" %>
<% Book.all.each do |book| %>
<br><%= check_box_tag "language_background_and_interest[book_ids][]", book.id %>
<%= book.name.humanize %>
<% end %>
</div>
<% end %>
Both the language_background_and_interest and books are joined together using a has_many_through like so:
class LanguageBackgroundAndInterest < ActiveRecord::Base
attr_accessible :book_ids
has_many :language_background_books
has_many :books, through: :language_background_books
end
class Book < ActiveRecord::Base
attr_accessible :name, :publisher
has_many :language_background_books
has_many :language_background_and_interests, through: :language_background_books
end
# Join Table
class LanguageBackgroundBook < ActiveRecord::Base
attr_accessible :language_background_and_interest_id, :book_id
belongs_to :language_background_and_interest
belongs_to :book
end
I am not sure why the books from the checkboxes don't get assigned to the appropriate background model. Any ideas?
PS: Granted, this design is rather ambiguous (Why not make books belong to an applicant?), but I currently want to put up a prototype and I am also constrained by a dubious requirement. So I need this working.
I ended up reviewing my model design and simplified it. I also switched to Simple Form to ease up working with my complex forms.
Related
So I am making an edit page that can edit animals and the owners to that animal. There is a join table involved which contains what Animal belongs to what Owner.
More precisely, Say you have:
<% form_for :animal, url: animal_path(#edit_animal), method: :patch do |edit| %>
... animal labels and fields to edit go here ...
<%= edit.fields_for :owners do |owner| %>
<%= owner.label :name, "Name" %>
<%= owner.text_field :name %>
<%end%>
<%=edit.submit 'Submit'%>
<%end%>
Model Associations:
AnimalOwner < ApplicationRecord
belongs_to :animal
belongs_to :owner
Owner < ApplicationRecord
has_many :animal_owners
has_many :animals, :through => :animal_owners
Animal < ApplicationRecord
has_many :animal_owners
has_many :owners, :through => :animal_owners
Basically, I am not sure if I am doing the form correctly for join tables. I also wanted to be able to display the data currently saved in the database using :value, but what how I would do that for a join table?
<%= owner.text_field :name, :value => what_goes_here? %>
If you are doing the Rails way, you don't need to mention the value for existing database data.
<%= owner.text_field :name%>
This should populate the data to above given field. Also its always better to use a single for for both "new" and "edit" methods. And for "edit" you can also use "PUT" as method type.
To use the field_for tag, you will also need to tell your Animal model that it accepts_nested_attributes_for :owners. This will allow the nested params to be massed assigned to the Animal instance.
That title's a mouthful.
So I have something like this:
class Company < ActiveRecord::Base
has_many :company_partner_associations
has_many :partners, through: :company_partner_associations
end
class CompanyPartnerAssociation
belongs_to :company
belongs_to :partner
end
class Partner
has_many :company_partner_associations
has_many :companies, through: :company_partner_associations
end
And on a company form, i'm trying to make a list of all Partners with a checkbox next to them. If I check one, it creates association. If I uncheck it destroys.
<%= f.fields_for :company_partner_associations, Partner.all do |p| %>
<%= f.check_box :partner_id %>
<% end %>
fails because the object getting passed is a Partner, so getting undefined partner_id on Partner
I'm sure there's a nifty solution out there! Thank you!
Do this:
<%= f.collection_check_boxes :partner_ids, Partner.all, :id, :name %>
No fields_for.
This will have to be accompanied in the controller with the following params:
params.require(:company).permit(:company, :params, partner_ids: [])
This should set the partner_ids in your #company model.
With HABTM, you can declare associative data by populating the "collection_singular_ids" method; HMT has the same method appended with the has_many relation:
Although this will replace the current associated objects, it is much simpler than calling f.fields_for - especially for picking partners.
--
You can also use collection_check_boxes which is meant for this purpose :)
Not totally sure this is the problem here, but I think it could be that your controller is just not permitting the array of partner ids. So in your company_partner_params in your company controller needs to permit something like partner_attributes: [:id]. The syntax might not be perfectly correct there, but if that's something you're missing, you should look around for that.
This is what I think the form should look like:
<%= form_for #company do |f| %>
<%= f.fields_for :partners, Partner.all do |partner| %>
...
<% end %>
<% end %>
Say I have the following polymorphic association:
class EmailAddress < ActiveRecord::Base
belongs_to :emailable, polymorphic: true
end
class Person < ActiveRecord::Base
has_many :email_addresses, as: :emailable, dependent: :destroy
accepts_nested_attributes_for :email_addresses
end
class Organization < ActiveRecord::Base
has_many :email_addresses, as: :emailable, dependent: :destroy
accepts_nested_attributes_for :email_addresses
end
I'm using the nested_form gem to help build a dynamic nested form where multiple email addresses can be added/removed when editing a person or organization. Ryan's documentation (modified for this example) states that if you use <%= f.fields_for :email_addresses %> then "it will look for a partial called "email_address_fields" and pass the form builder as an f variable to it."
This is handy, but in my case the email address fields partials would be exactly the same for both people and organizations. Instead of having both /app/views/people/_email_address_fields.html.erb and /app/views/organizations/_email_address_fields.html.erb, is there a way to tell the f.fields_for method to use a different partial (e.g., one created in /app/views/email_addresses/_fields.html/erb or something similar)?
I thought of the following:
<%= f.fields_for :email_addresses do |email_address_form| %>
<%= render partial: 'email_addresses/fields', locals: { f: email_address_form } %>
<% end %>
Is there a better way though?
No, I don't believe there is a better way, although you could make a helper method to remove duplication if you really want to. We use exactly the same strategy for nested link forms:
<%= f.fields_for :links do |link_form| %>
<%= render partial: "shared/link_fields", locals: { f: link_form } %>
<% end %>
I have following arragement
The Pizza model, to create a list of pizzas that can be ordered by customers, also gets associated with order, so to indicate which pizza has been ordered.
class Pizza < ActiveRecord::Base
has_many :pizza_orders
has_many :orders, :through => :pizza_orders
has_and_belongs_to_many :toppings
end
Option model, to create a list of options that can be associated with certain pizzas, also gets associated with the join table for each pizza order, to specify which pizza has the topping ordered.
class Topping < ActiveRecord::Base
has_and_belongs_to_many :pizzas
has_and_belongs_to_many :pizza_orders
end
The join table for pizza and topping, this is needed because without it, you can not specify which toppings can or can not be ordered with a pizza. After all, having peperoni topping listed to a vegetarian pizza might offend someone.
class PizzasToppings < ActiveRecord::Base
belongs_to :pizza
belongs_to :topping
end
The order model, this just holds all the join tables together.
class Order < ActiveRecord::Base
has_many :pizza_orders
has_many :pizzas, :through => :pizza_orders
end
The join table between pizza and order, this many to many is a has many through, and not a has and belongs to many since in Rails you cannot directly manipulate HBATM join tables (as far as I have tried), and you need to be able to because of the options relation ship.
class PizzaOrder < ActiveRecord::Base
belongs_to :pizza
belongs_to :order
has_and_belongs_to_many :toppings
end
The join table to indicate which toppings have been chosen for a particular pizza in a order.
class PizzaOrdersToppings < ActiveRecord::Base
belongs_to :pizza_orders
belongs_to :topping
end
Then I have an admin page to create and associate the Pizzas and toppings.
But I don't know how to create the orders form. The user should be able to add a pizza and select one or many toppings which are already created
Its a bit old screencast Nested model form part 1 made by ryan bates but i hope it helps you , also there is a revised version of this screencast.
Sorry I was late to respond.
Okay, haven't tested this, but hope it gets you the idea. In order for it to work, this sample relies on,
simple_form
the ryan bates dynamic nested form
I have to apologize, this answer is lacking a large part of it, you need to re-render the link_to_add_fields part every time you change the <%= f.association :pizzas %> value so that the hidden field that contains the toppings match the pizza that has been selected.
Sorry I couldn't get you completly through, but I hope this points you in the right direction.
_form.html.erb
<%= simple_form #order do |f| %>
<%= f.simple_fields_for :pizza_orders do |pizza_orders_fields| %>
<%= f.association :pizzas %>
<%= render partial: "pizza_order_fields", locals: {f: pizza_orders_fields}%>
<%= link_to_add_fields "Add", f, :pizza_orders %>
<% end %>
<% end %>
pizza_order_fields.html.erb would look like
<fieldset>
<%= f.hidden_field :_destroy %>
<%= link_to "Delete", '#', class: "remove_fields btn btn-danger" %>
<%= f.association toppings_pizza_orders, collection: f.object.pizza.toppings %>
</fieldset>
I have a one-to-one relationship between user and goal. I want to build a form that shows the goal of a user. The problem is that my code only works when the user already has a goal defined. The text field is not rendered when no goal is present.
<%= user_builder.fields_for :goal do |goal_builder| %>
<%= goal_builder.text_field :goal %>
<% end %>
Does Rails provide an easy way to do this?
This is how I would do it :
class User < ActiveRecord::Base
has_one :goal
accepts_nested_attributes_for :goal
after_initialize do
self.goal ||= self.build_goal()
end
end
You can do this very easily with accepts_nested_attributes_for.
In the view, as you had:
<%= user_builder.fields_for :goal do |goal_builder| %>
<%= goal_builder.text_field :goal %>
<% end %>
In the User model:
class User < ActiveRecord::Base
has_one :goal # or belongs_to, depending on how you set up your tables
accepts_nested_attributes_for :goal
end
See the documentation on nested attributes, and the form_for method for more information.