How to show select menu for two models? - ruby-on-rails

I'm using Simple Form and don't how you would show the values of 2 associations.
A Price can belong to a service or product but not both at the same time.
Price
# service_id, product_id
belongs_to :services # service.name
belongs_to :products # product.name
end
Instead having my simple form look like this:
<%= f.association :product, :input_html => { :class => "span5 } %>
<%= f.association :service, :input_html => { :class => "span5 } %>
I want to turn it into one field instead.
What is the way with simple_form_for?
What about with a regular form_for?

I think better way to do is to use polymorphic association.
class Price
belongs_to :pricable, polymorphic: true
end
class Product
has_one :price, as: :priceable
end
class Service
has_one :price, as: :priceable
end
Then, in your form, you can use:
<%= form_for [#priceable, Price.new]
where #priceable is a product or a service.

Related

Rails nested form with unknown columns

I'm creating an admin interface where the admin (of a company) can add custom fields to their employees.
Example:
Models:
Employee: Basic info like name, contact info, etc (has_many employee_field_values)
EmployeeFields: These are the dynamic ones the admin can add (every company has different needs, it could be anything), lets say favorite_food
EmployeeFieldValues: The actual values based on the fields above, say pizza (belongs_to both models above)
What's a smart way of adding the EmployeeFieldValues fields while editing an employee?
I'm trying something simple like this, but not sure if I like it
# Controller
#custom_fields = EmployeeFields.all
# View
<%= form_for(#employee) do |f| %>
<%= f.text_field :first_name %>
<% #custom_fields.each do |custom_field| %>
<%= custom_field.name %>
<%= text_field_tag "employee_field_values[#{custom_field.name}]" %>
<% end %>
<%= f.submit :save %>
<% end %>
And then when updating, params[:employee_field_values] gives this:
<ActionController::Parameters {"favorite_food"=>"pizza"}>
So, not sure if this is a good direction, also I'm not sure how to handle future edits to an employee's custom_fields if they change.
I think it will be better to use EmployeeField as nested model and EmployeeFieldValue for select field.
For example:
Models
class Employee < ActiveRecord::Base
validates :name, presence: true
has_many :employee_field_values
accepts_nested_attributes_for :employee_field_values, reject_if: ->(x) { x[:value].blank? }
end
class EmployeeFieldValue < ActiveRecord::Base
belongs_to :employee
belongs_to :employee_field
end
class EmployeeField < ActiveRecord::Base
has_many :employee_field_values, inverse_of: :employee_field, dependent: :destroy
validates :title, presence: true, uniqueness: true
end
Controller
class EmployeesController < ApplicationController
def new
#employee = Employee.new
#employee.employee_field_values.build
end
end
View
= simple_form_for #employee, url: '/' do |f|
= f.input :name
= f.simple_fields_for :employee_field_values do |ff|
= ff.input :value
= ff.input :employee_field_id, collection: EmployeeField.all.map{|x| [x.title, x.id]}
Also you need to make buttons for adding/removing :employee_field_value, and you can do it with gem cocoon for example
OR you can build all objects in controller(for each EmployeeField) and do without select box

Nested forms with multiple table inheritance

How do I build a nested form for objects using multiple table inheritance in rails? I am trying to make a nested form to create an object using a model with a has_many relationship to another set of models that feature multi-table inheritance. I am using formtastic and cocoon for the nested form and the act_as_relation gem to implement the multiple table inheritance.
I have the following models:
class Product < ActiveRecord::Base
acts_as_superclass
belongs_to :store
end
class Book < ActiveRecord::Base
acts_as :product, :as => :producible
end
class Pen < ActiveRecord::Base
acts_as :product, :as => :producible acts_as :product, :as => :producible
end
class Store < ActiveRecord::Base
has_many :products
accepts_nested_attributes_for :products, :allow_destroy => true, :reject_if => :all_blank
end'
For this example, the only unique attribute that book has compared to other products is an author field. In reality, I have a number of unique attributes for book which is why I chose multi-table inheritance over the more commonplace single table inheritance.
I am trying to create a nested form that allows you to create a new store with products. Here's my form:
<%= semantic_form_for #store do |f| %>
<%= f.inputs do %>
<%= f.input :name %>
<h3>Books/h3>
<div id='books'>
<%= f.semantic_fields_for :books do |book| %>
<%= render 'book_fields', :f => book %>
<% end %>
<div class='links'>
<%= link_to_add_association 'add book', f, :books %>
</div>
<% end %>
<%= f.actions :submit %>
<% end %>
And the book_fields partial:
<div class='nested-fields'>
<%= f.inputs do %>
<%= f.input :author %>
<%= link_to_remove_association "remove book", f %>
<% end %>
</div>
I get this error:
undefined method `new_record?' for nil:NilClass
Based on reading the issues on the github page for act_as_relation, I thought about making the relationship between store and books more explicit:
class Product < ActiveRecord::Base
acts_as_superclass
belongs_to :store
has_one :book
accepts_nested_attributes_for :book, :allow_destroy => true, :reject_if => :all_blank
end
class Book < ActiveRecord::Base
belongs_to :store
acts_as :product, :as => :producible
end
class Store < ActiveRecord::Base
has_many :products
has_many :books, :through => :products
accepts_nested_attributes_for :products, :allow_destroy => true, :reject_if => :all_blank
accepts_nested_attributes_for :books, :allow_destroy => true, :reject_if => :all_blank
end
Now, I get a silent error. I can create new stores using the form, and cocoon allows me to add new book fields, but when I submit the store gets created but not the child book. When, I go through the `/books/new' route, I can create a new book record that spans (the products and books table) with no problem.
Is there a workaround to this problem? The rest of the code can be found here.
Maybe you could:
Build the books relation manually on your stores_controller#new action
#store.books.build
Store manually the relation on you stores_controller#create action
#store.books ... (not really confident on how to achieve it)
Keep us posted.
You might want to consider creating your own form object. This is a RailsCast pro video, but here are some of the examples in the ASCIIcast:
def new
#signup_form = SignupForm.new(current_user)
end
This signup form can include relations to your other objects, just as you would in your original controller code:
class SignupForm
# Rails 4: include ActiveModel::Model
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
validates_presence_of :username
validates_uniqueness_of :username
validates_format_of :email, with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/
validates_length_of :password, minimum: 6
def persisted?
false
end
def subscribed
subscribed_at
end
def subscribed=(checkbox)
subscribed_at = Time.zone.now if checkbox == "1"
end
def generate_token
begin
self.token = SecureRandom.hex
end while User.exists?(token: token)
end
end
Here is the link to the RailsCast. Getting a pro membership might be worth your time. I have been getting lucky with a membership through www.codeschool.com where you can get 'prizes' when you finish courses:
RailsCast:
http://railscasts.com/episodes/416-form-objects

Rails 3.2: multiple nested data from one model

How to create form and action for multiple nested attributes if:
LineItem:
has_many :item_options, :dependent => :destroy
has_many :product_options, :through => :item_options
ProductOption:
belongs_to :product
belongs_to :option
has_many :item_options
has_many :line_items, :through => :item_options
ItemOption:
attr_accessible :line_item_id, :product_option_id
belongs_to :line_item, :foreign_key => "line_item_id"
belongs_to :product_option,:foreign_key => "product_option_id"
When I'm creating new LineItem, I need to create new ItemOption(s). This is my form:
<%= form_for(LineItem.new) do |f| %>
<%= f.hidden_field :product_id, value: #product.id %>
<%= f.fields_for :item_options do |io| %>
<% #product.options.uniq.each do |o| %>
<%= o.name %>:
<%= io.collection_select :product_option_id, o.product_options.where(:product_id => #product.id), :id, :value %>
<% end %>
<%= f.submit %>
<% end %>
When I'm clicking on Add To Cart, I've get:
ItemOption(#70296453751440) expected, got Array(#70296430421140)
When Adding accepts_nested_attributes_for :item_options to LineItem, my selects not diplayed :(
With
<%= select_tag "product_option_id", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
#item_options not created:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"/WM5/MqPn1yCxjKWoJQmjfko2pR4RiYV0S2KeTTpA3w=", "line_item"=>{"product_id"=>"1"}, "product_option_id"=>"5", "commit"=>"add"}
And last one, I've create action like this:
#line_item = LineItem.new(params[:line_item])
#line_item.item_options.build
....
Where am I wrong? :( I'm totally confused.
ps. similar question Rails 3.2 has_many through form submission
This is form:
Looks this line:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"/WM5/MqPn1yCxjKWoJQmjfko2pR4RiYV0S2KeTTpA3w=", "line_item"=>{"product_id"=>"1"}, "product_option_id"=>"5", "commit"=>"add"}
The parameter product_option_id is outside line_item hash, and will be inside. Maybe you need write the select like this:
<%= select_tag "line_item[product_option_id]", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
I'm not sure, but maybe is this. Maybe I need more information, like the exact line where is failing.
Extra, the :foreign_key => "line_item_id" and :foreign_key => "product_option_id" are not necesary, because, the belongs_to model name is the same and will use these foreign_key. From api.
Specify the foreign key used for the association. By default this is
guessed to be the name of the association with an “_id” suffix. So
a class that defines a **belongs_to :person** association will use
“person_id” as the default :foreign_key. Similarly, belongs_to
:favorite_person, :class_name => "Person" will use a foreign key of
“favorite_person_id”.
Edit
Sorry, the unknown attribute: product_option_id is because the attribute name is product_option_ids, and is an array, not a unique value. For a has_many relationship, the column name is collection_singular_ids, and the select should be:
<%= select_tag "line_item[product_option_ids][]", options_from_collection_for_select(o.product_options.where(:product_id => #product.id), :id, :value) %>
This should work, I think :)...

Insert more than one item from a belongs_to association using nested forms

in my Rails way, I have just found another question to the commmunity.
I have the following project: I have a calendar which render me the events that any client have dealed with my company. If I want to insert a new event with only one client, I have no problem, but if I want to insert a new event with more than one client, I have a problem.
But it's been impossible to insert more than one client at the same time. I know that with this configuration, Rails only accepts one client for every instance of event, and one solution could be change the association model between Event and Client, but it makes no sense for me (event has_many clients and client belongs_to events... sounds weird). So, this post it's related to compile options from the community.
This is my code (I'm using the nested_form gem by Ryan Bates [github.com/ryanb/nested_form.git]):
UPDATE: By the moment, I introduce a new model Group, in this way:
models/group.rb
class Group < ActiveRecord::Base
has_many :clients
has_many :events
accepts_nested_attributes_for :clients
accepts_nested_attributes_for :events
attr_accessible :events_attributes, :clients_attributes
end
models/client.rb
class Client < ActiveRecord::Base
has_many :events
belongs_to :group
accepts_nested_attributes_for :events
accepts_nested_attributes_for :group, :update_only => true
attr_accessible :name, :surname, :email, :group_attributes, :events_attributes
end
models/event.rb
class Event < ActiveRecord::Base
belongs_to :group
accepts_nested_attributes_for :group, :update_only => true
attr_accessible :title, :group_id, :starts_at, :ends_at, :group_attributes
end
views/events/_form.html.erb
<%= simple_nested_form_for #event do |f| %>
<%= f.input :title %>
<%= f.fields_for :group do |group_form| %>
<%= group_form.fields_for :clients do |client_form| %>
<%= client_form.input :name %>
<%= client_form.input :surname %>
<%= client_form.input :email, :as => :email %>
<%= client_form.link_to_remove "Remove this client" %>
<% end %>
<%= group_form.link_to_add "Add another client", :clients %>
<% end %>
<%= f.input :starts_at, :as => :datetime %>
<%= f.input :ends_at, :as => :datetime %>
<%= f.button :submit %>
<% end %>
But know, my problem is that, when I create an event for one group, this group is successfully create when I insert ONLY ONE client. When I try to insert two or more clients I get the next:
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: new_1332430522879):
app/controllers/events_controller.rb:44:in `new'
app/controllers/events_controller.rb:44:in `create'
Ah! And I forget to comment before (but I think that is not relevant for that), that I'm using Ruby 1.9.3-p125 and Rails 3.2.2
Any ideas?
Thanks in advance...
Foncho

Assigning a nested attribute with Formtastic

I've been trying to figure this one out for a while but still no luck. I have a company_relationships table that joins Companies and People, storing an extra field to describe the nature of the relationship called 'corp_credit_id'. I can get the forms working fine to add company_relationships for a Person, but I can't seem to figure out how to set that modifier field when doing so. Any ideas?
More about my project: People have many companies through company_relationships. With that extra field in there I am using it to group all of the specific relationships together. So I can group a person's Doctors, Contractors, etc.
My models:
Company.rb (abridged)
class Company < ActiveRecord::Base
include ApplicationHelper
has_many :company_relationships
has_many :people, :through => :company_relationships
Person.rb (abridged)
class Person < ActiveRecord::Base
include ApplicationHelper
has_many :company_relationships
has_many :companies, :through => :company_relationships
accepts_nested_attributes_for :company_relationships
company_relationship.rb
class CompanyRelationship < ActiveRecord::Base
attr_accessible :company_id, :person_id, :corp_credits_id
belongs_to :company
belongs_to :person
belongs_to :corp_credits
end
My form partial, using formtastic.
<% semantic_form_for #person do |f| %>
<%= f.error_messages %>
<% f.inputs do %>
...
<%= f.input :companies, :as => :check_boxes, :label => "Favorite Coffee Shops", :label_method => :name, :collection => Company.find(:all, :conditions => {:coffee_shop => 't'}, :order => "name ASC"), :required => false %>
So what I would like to do is something like :corp_credit_id => '1' in that input to assign that attribute for Coffee Shop. But formtastic doesn't appear to allow this assignment to happen.
Any ideas on how to do this?
Are you looking for something like
<% semantic_form_for #person do |form| %>
<% form.semantic_fields_for :company_relationships do |cr_f| %>
<%= cr_f.input :corp_credit_id %>
<% end %>
It is in the documentation

Resources