One to many relationship in ROR using Formtastic - ruby-on-rails

following up with this topic:
(Rails) How to display child records (one-to-many) in their parent's form?
I am creating a category that may have many products. So, I use the Formtastic as user Chandra Patni suggested. But I find there is a problem when I added attr_accessible to the product.rb.
class Product < ActiveRecord::Base
validates_presence_of :title, :price
validates_numericality_of :price
validates_uniqueness_of :title
attr_accessible :category_id, :name
belongs_to :category
end
and this is the category.rb:
class Category < ActiveRecord::Base
attr_accessible :name
has_many :products
end
After I added the attr_accessible :category_id, :name , the validation gets crazy, no matter I type, it treats me as null in the text value. But after I remove the attr_accessible :category_id, :name all stuff works.
One more thing, in the products/new.html.erb , I created this to input the product information,
<% semantic_form_for #product do |f| %>
<% f.inputs do %>
<%= f.input :title %>
<%= f.input :price %>
<%= f.input :photoPath %>
<%= f.input :category %>
<% end %>
<%= f.buttons %>
<% end %>
But I find that it return the :category id instead of the category name. What should I do?
Thx in advanced.

You will need to add other attributes to attr_accessible for rails to perform mass assignment.
attr_accessible :category_id, :name, :title, :price, :photoPath
Rails will only do mass assignment for attributes specified in attr_accessible (white list) if you have one. It is necessary from security point of view. Rails also provides a way to blacklist mass assignments via attr_protected method.
You should see a drop down for category if you have name attribute in your Category model. See this and this.
class Category < ActiveRecord::Base
has_many :products
attr_accessible :name
end

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

Reading value with association (simple_form)

I have such models:
class Grade < ActiveRecord::Base
has_many :question_grades
end
class QuestionGrade < ActiveRecord::Base
belongs_to :grade
belongs_to :question
# it has integer :number
end
class Question < ActiveRecord::Base
# it has string :label
end
I have a simple_form for the 'grade' model, which iterates question_grades:
<%= simple_form_for #grade, :url => "/homeworks/update_grade", :method => :post do |f| %>
<%= f.simple_fields_for :question_grades do |q| %>
<%= q.association :question %>
<%= q.input :number, :collection => 0..2, label: false%>
</div>
</div>
This form creates an editable form for each 'question_grade', where allows visitors to edit 'number' attribute of question_grade. I also want to show a label by using the value, 'question_grade.question.label'. I created an association with 'q.association :question' but it creates an editable input form item. I want to access a value in the association. How can I do that?
When you do
<%= q.association :question %>
you are creating a field to edit this association, as you can see.
What do you need, is to access the q.object, defined as attr_reader here .
in this case, it will be your QuestionGrade instance.
so this:
<%= q.object.question.label %>
may solve your problem.

simple-form grouped collection select for has many through association

I have three models as shown
class Location < ActiveRecord::Base
attr_accessible :location_name
has_many :areas
has_many :restaurants, through: :areas
end
class Area < ActiveRecord::Base
attr_accessible :area_name, :location_id
belongs_to :location
has_many :restaurants
end
class Restaurant < ActiveRecord::Base
attr_accessible :description, :menu, :restaurant_name, :area_id
belongs_to :area
end
Am using simple-form gem and i want create a new restaurant and select a Location first which has many areas and the correct areas associated with a location to be automatically selected. Then i narrow down to a single area. Similar in concept to say how someone would select Continents and then be narrowed down to a country in a particular continent. Is there a way to achieve this using simple_form.?
Do i have anything extra to the new action in the restaurant controller?
This is my view so far for creating a new restaurant
<%= simple_form_for #restaurant do |f| %>
<%= f.input :restaurant_name %>
<%= f.input :description %>
<%= f.input :menu %>
<%= f.input :area_id,collection: #locations, as: :grouped_select, group_method: :areas%>
<%= f.button :submit %>
<% end %>
This doesnot work as expected. I have already populated my database with Locations and Areas. Any ideas?
You need to pass the options the other way around, collection is the parent group, not the child group. In your case you need:
<%= f.input :area_id,collection: #areas, as: :grouped_select, group_method: :locations %>

How to display text of category, has-one belongs to associaton

Ok i have two models:
class Treatment < ActiveRecord::Base
attr_accessible :category_id, :content, :date, :patient_id
has_one :category
end
class Category < ActiveRecord::Base
attr_accessible :text
has_many :treatments
end
In my application i tried now to display the text of the category instead of the id for each treatment. Among others i tried this:
<% #treatments.each do |f| %>
<%= f.content %>
<%= f.date %>
<%= f.category.try(:text) %>
<% end %>
But i get the error:
SQLite3::SQLException: no such column: categories.treatment_id
So how can i get the text of the category instead of the id? Thanks
It looks as though you've got an issue with your model relationships. If you're after a standard one-to-many relationship then you need to change
has_one :category
to
belongs_to :category
in your Treatment model.

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

Resources