Represent associated model with simple_form_for - ruby-on-rails

I have the following models where UserTreatment is essentially a lookup table but it has another field called instance_cost which stores an integer against each relationship.
class User < ActiveRecord::Base
has_many :user_treatments
has_many :users, :through => :user_treatments
end
class UserTreatment < ActiveRecord::Base
attr_accessible :instance_cost
belongs_to :user
belongs_to :treatment
end
class Treatment < ActiveRecord::Base
attr_accessible :name
has_many :user_treatments
has_many :users, :through => :user_treatments
end
So I can do things like this to get the first instance cost for user id 14
1.9.3p429 :181 > User.find(14).user_treatments.first.instance_cost
=> 100
and this to get the name of the treatment
1.9.3p429 :181 > User.find(14).user_treatments.first.treatment.name
=> "Sports Massage"
However I have a problem representing them in a form using simple_form_for
<% simple_form_for #user do |f| %>
# This sucessfully gives us the checkboxes of all treatments and stores them in the UserTreatments table
<%= f.collection_check_boxes(:treatment_ids, Treatment.all, :id, :name) %>
<%= f.fields_for :user_treatments do |pt| %>
<tr>
<td>
<!-- I WANT THE NAME OF THE TREATMENT HERE -->
</td>
<td><span>£</span> <%= pt.input :instance_cost, :as => :string, wrapper: false, label: false %></td>
</tr>
<% end %>
end
There are two things I need to do.
Show the name of the treatment (how do I do express User.user_treatments.treatment.name with simple_form ?)
Set the instance_cost correctly. Its currently not getting set at all.

When you do fields_for for a nested association then you need to add the following in your User model:
accepts_nested_attributes_for :user_treatments
Otherwise, it will not save the information.
And to access the name of the treatment, you could go through the object method of the form creator object, like this:
<%= f.fields_for :user_treatments do |pt| %>
<tr>
<td><%= pt.object.treatment.name %></td>
...
</tr>
<% end %>

Related

How do I get the table column data from one model into the view of another?

I want the customer name to appear in the customer name column on one of my model view pages, but I can't seem to figure out how to do this.
Here are my associations:
Customer Model is -
class Customer < ActiveRecord::Base
has_many :appointments, :dependent => :destroy, :as => :customer
has_many :birds, :dependent => :destroy, :as => :customer
end
Bird Model is -
class Bird < ActiveRecord::Base
belongs_to :customer
has_one :appointment
end
I've also added this to the Bird model index view -
<tbody>
<% #birds.each do |bird| %>
<tr data-link="<%= bird_path(bird) %>">
<td><%= bird.customer_id %></td>
<td><%= bird.name %></td>
<td><%= bird.breed %></td>
<td><%= bird.color %></td>
<td><%= bird.age %></td>
</tr>
<% end %>
The customer parameter I'd like to pass into the customer name column on the birds index view page is customer.name, or :name. If I try that, I get an undefined methods error on my /birds page.
Thanks!
I would expect that this should work:
<%= bird.customer.name %>
Or - if you have birds without an customer - you might want avoid exceptions like this:
<%= bird.customer.try(:name) %>
Or - less error prone - add the following to your bird model:
delegate :name, to: :customer, allow_nil: true, prefix: true
And use it in your views like this:
<%= bird.customer_name %>
You need to use in your view like this :
<%= bird.customer.name %>
In your controller, for the bird index page:
when you query for Bird.all, do Bird.all.includes(:customer)
then you will have access to <%= bird.customer.name %> in the view

Join Table Quantity

I'm learning Rails building an ordering system and I'm stuck trying to build a form for Orders. My models look like this:
class Restaurant < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :restaurant
has_many :order_recipes, dependent: :destroy
has_many :recipes, through: :order_recipes
end
class Recipe < ActiveRecord::Base
belongs_to :restaurant
has_many :order_recipes
has_many :orders, through: :order_recipes
end
I used to handle the input for Recipes using checkboxes, which only allowed me to add one of each recipe:
<%= form_for([#restaurant, #order]) do |f| %>
<%= f.label :Table_Number %>
<%= f.number_field :table_id %>
<strong>Recipes: </strong>
<br>
<%= f.collection_check_boxes :recipe_ids, #recipes, :id, :name do |cb| %>
<% cb.label(class: "checkbox-inline input_checkbox") {cb.check_box(class: "checkbox") + cb.text} %>
<% end %>
<%= f.collection_select(:recipe_ids, #recipes, :id, :name) %>
<%= f.submit(#order.new_record? ? "Create Order" : "Edit Order", class: "btn btn-success") %>
<% end %>
But now I need to also handle quantities. So I added the "quantity" column to the order_recipes table. And I can't figure out how to build the proper form to be able to submit an Order object, with an order_recipe array of objects containing [recipe_id, order_id, quantity] per row. I'm also opened to using formtastic if it makes things easier, although I'm not very good with it yet.
ETA: Since the quantity field is on the orders_recipes table, you'll want to create an #orders_recipes object with all the correct recipe_ids instead:
#orders_recipes = #recipes.map{|r| #order.order_recipes.build(recipe: r)}
Then you can use the FormHelper's fields_for method:
<%= f.fields_for :order_recipes, #order_recipes do |orf| %>
<%= orf.hidden_field :recipe_id %>
Quantity: <%= orf.number_field :quantity %>
<%- end -%>
If desired, you'll need to "manually" remove order_recipes with nil or 0 values for quantity.
For this to work, you need an accepts_nested_attributes_for in your model, like so:
class Order < ActiveRecord::Base
…
accepts_nested_attributes_for :order_recipes
end

Creating a resource that belongs_to another resource

Here are my relevant models:
class ListItem < ActiveRecord::Base
belongs_to :inventory_item
belongs_to :shopping_list
belongs_to :item
end
class ShoppingList < ActiveRecord::Base
has_many :list_items
belongs_to :user, :foreign_key => :user_id
end
class InventoryItem < ActiveRecord::Base
belongs_to :item, :foreign_key => :item_id
belongs_to :vendor
has_many :list_items
end
I want to have a button to create ListItems that belong to a user specified list that they own. The new ListItem also needs to be passed the respective :item_id and :inventory_item_id. Here's the relevant part of my current view:
<tr>
<% item.inventory_items.each do |product| %>
<td><%= button_to "#{product.price}",
{:controller => :list_items,
:action => 'create',
:id => #what goes here??,
:method => :create %></td>
<% end %>
</tr>
And my ListItems controller create method:
def create
ListItem.create
flash[:success] = "List Item Added."
redirect_to search_results_path(params[:search])
end
Clearly my create method isn't all that useful right now because it just creates a ListItem with no attributes other than :id. What's the best way to pass the appropriate parameters to my controller? Any help is much appreciated! Thanks in advance.
After doing a bunch of snooping around SO etc. I think the best way to accomplish this is to use a form with hidden fields, as below:
<%= form_tag("/list_items", method: "post") do %>
<%= hidden_field_tag(:item_id, item.id) %>
<%= hidden_field_tag(:inventory_item_id, product.id) %>
<%= hidden_field_tag(:shopping_list_id, ShoppingList.first.id) %>
<%= submit_tag("#{product.price}") %>
This is working well for me and is cleaner in this instance than using a button_to.

Rails: Create form for #score while in different model no direct associations

I want to create a multiple form for editing scores from a different model.
The main model is a Formrule model that consists of a habtm association with a Scoretype model
and has a habtm association with a Room model.
Both models are used to query a Scores model resulting in a #scores instance. It is for this instance I want to create a form, but the problem is that no field_for are being created. I know that the #scores is populated correctly, but the form does not show up.
This is the form as I have it now
<%= form_tag '/scores/update_scores' do %>
<table>
<tr>...</tr>
<% for score in #scores %>
<% fields_for :scores, score do |score| %>
<tr>
<td>
<%= score.hidden_field(:form_id) %>
<%= score.hidden_field(:team_id) %>
<%= score.hidden_field(:scoretype_id) %>
</td>
<td>
<%= score.number_field :scorevalue %>
</td>
</tr>
<% end %>
<% end %>
</table>
<%= submit_tag 'Update' %>
<% end %>
And these are the Models:
Formrule
class Formrule < ActiveRecord::Base
belongs_to :form
has_and_belongs_to_many :scoretypes
has_and_belongs_to_many :rooms
has_many :teams, :through => :rooms
end
Scoretype
class Scoretype < ActiveRecord::Base
has_many :scores
has_and_belongs_to_many :formrules
end
Room
class Room < ActiveRecord::Base
has_many :teams
has_and_belongs_to_many :formrules
end
Team
class Team < ActiveRecord::Base
has_many :scores
belongs_to :room
belongs_to :group
end
Score
class Score < ActiveRecord::Base
belongs_to :form
belongs_to :team
belongs_to :scoretype
validates_uniqueness_of :id, :scope => [:team, :scoretype]
end
And finally, the used controller (Formrule)
def show
#formrule = Formrule.find(params[:id])
#scoretypes = #formrule.scoretypes.all.collect
#rooms = #formrule.rooms.all.collect
#teams = Team.find(:all, :conditions => {:room_id => #rooms})
#scores = Score.order("team_id").all(:conditions => {:scoretype_id => #scoretypes, :team_id => #teams})
...
end
Why is the form not showing up? any suggestions?
Thank you all in advance!
Try using <%= fields_for ... %> instead of <% fields_for ...%>.

form_for for relation table with type of many to many relation

My goal is to display select box for each relation for users and specific project.
All users need to be listed but only project users have some type of relation. Other users have none selected in theirs select box.
I have this model:
class Project < ActiveRecord::Base
belongs_to :company
has_many :tasks, :order => 'state_type_id ASC'
has_many :project_user_relations
has_many :users, :through => :project_user_relations
def t_name
name.camelcase
end
end
class User < ActiveRecord::Base
belongs_to :company
has_many :tasks , :foreign_key => :assigned_user_id
has_many :project_user_relations
has_many :projects, :through => :project_user_relations
def full_name
firstname + ' ' + lastname
end
def relation_to(project)
relation=ProjectUserRelation.find_by_project_id_and_user_id(project.id, id)
relation ||= relation=ProjectUserRelation.new
end
end
class ProjectUserRelation < ActiveRecord::Base
belongs_to :project
belongs_to :user
has_one :project_user_relation_type
end
class ProjectUserRelationType < ActiveRecord::Base
def t_name
I18n.t("app.projects.users.relation.type."+code)
end
end
I want make a form to display all users, with collection_select.
I used code:
def edit_all
#project = Project.find(params[:project_id])
#users = User.all
....
in my controler
routes works ok.
in my view:
<% #users.each do |user| %>
<%= f.fields_for :users, user do |user_fields| %>
<tr class="reference" rel="<%= parent_user_path(user) %>" >
<td class="name"><%= link_to user.full_name, parent_user_path(user) %></td>
<td class="email"><%= mail_to user.email %></td>
<td class="type">
<%= user_fields.fields_for user.relation_to #project do |relation_fields| %>
<%= relation_fields.collection_select :project_user_relation_type, ProjectUserRelationType.all, :id, :t_name, {:include_blank => false, :prompt => t("helpers.select.prompt") } %>
<% end %>
</td>
</tr>
<% end %>
<% end %>
or for test:
<%= f.fields_for :users, #users do |xuser_fields| %>
<% logger.debug "#{self.to_s} xuser_fields = #{xuser_fields.object.inspect} ;" %>
<tr>
<td><%= xuser_fields.text_field :firstname %></td>
<td></td>
<td></td>
<td></td>
</tr>
<% end %>
but notnihng woks right
first one generates wrong name in html:
select id="project_users_project_user_relation_project_user_relation_type" name="project[users][project_user_relation][project_user_relation_type]"
second one generates error:
undefined method `firstname' for # Array:0x4d03658
Can you help me to solve this situation.
PS:sorry for long code :(
SOLUTION (probably - solved by reading RoR sources)
I found sollution i thing.
A method
def name_attributes=(attributes)
# Process the attributes hash
end
in Project model was missing.
It is unbelievable sollution :].
There is also exact syntax after fields_for: :name, #some_collection, where name must be exactly same name as in the beginign of mentioned def in Model.

Resources