Handling a belongs_to in a form - ruby-on-rails

Editx2: The short short version: I think I found my answer:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
Under heading One-To-One , I think this is what i want?
If so I will just close this out.
EDIT: I found this here:
http://railscasts.com/episodes/196-nested-model-form-part-1?autoplay=true
This is close to what I want, but it has many things under the survey (in my case a group) and while I will have many addresses for a group this is in a different area (as locations), but in the main form when the group is created I have ONE address that is the billing address for a group. So I am not sure how to have like the form look all nice and update the #group.billing_address as described below.
I have a model called Group, in it it has a billing address. This billing address is of type 'Address'. In the group model it looks like
belongs_to :billing_address, class_name: 'Address', foreign_key: 'billing_address_id'
In my group_test.rb file I can test this functionality very easily:
test 'can add a billing address to a group' do
group = Group.new
group.group_name = 'Group test with provider'
adr = Address.new
adr.city = 'Las Cruces'
adr.state = 'New Mexico'
adr.zip = '88012'
adr.address_line_one = '382 Dark side of moon'
adr.address_line_two = ''
adr.save
group.billing_address = adr
group.save
assert_not_nil group.billing_address, 'Group did not have any billing address'
end
My question is how would I do the above in a form? Since my controller group_controller.rb does this on new:
def new
#group=Group.new
end
It doesn't do anything like:
def new
#group=Group.new
#group.billing_address.new
end
To which in my view input tags for the form can't look something like:
<table>
<tr>
<th>
<%= f.label "Group Name" %>
</th>
</tr>
<tr>
<td>
<%= f.text_field :group_name , size: 50 %>
</td>
</tr>
<tr>
<th>
<%= f.label "Billing Address City" %>
</th>
</tr>
<tr>
<td>
<%= f.text_field :billing_address.city, size: 50 %>
</td>
</tr>
</table>
The above does not work. I didn't expect it to, just trying to demonstrate what I am trying to do. Is even my thinking right? or do I have to split the data up like I do sort of more in my test, and do it according to this answer I found on multiple models in a form:
Rails - User Input for Multiple models on a single form - How
Get the data that way and hook it back together in the controller on the create or update method?

Related

Sorting an index through an associated table?

I have an index that displays all of the current "dprojects" created. I'm working on being able to click the table headers to sort the data by that parameter. I have this all working except for one column. This column displays our customers by the number we've assigned them. For example, "Customer A" is "008". The "dprojects" table has a column for customer ID, and the "schools" table has columns for both the ID and the actual name of the customer.
Because it is a "dprojects" index, the table is sorting by the ID associated with the customer, and not the customer's name. How can I get it to sort alphabetically by name? Here's my code:
view: (dname is the customer name within the school model)
<table>
<thead>
<tr style="border-bottom: 2px solid black;">
<th> <%= sortable "scode", "School" %></th>
</tr>
</thead>
<tbody>
<% #dprojects.where.not(status: "Completed").each do |dproject| %>
<tr>
<td width="20%" class="dotted"><%= dproject.school.dname[0,25] + "..." %></td>
</tr>
<% end %>
</tbody>
</table>
model:
class Dproject < ActiveRecord::Base
belongs_to :school, foreign_key: 'scode'
end
controller:
def index
#dprojects = Dproject.order(params[:sort])
respond_with(#dprojects)
end
helper:
module DprojectsHelper
def sortable(column, title = nil)
title ||= column.titleize
link_to title, :sort => column
end
end
I thought I would be able to modify the view with the line:
<th> <%= sortable "dproject.school.dname", "School" %></th>
but that doesn't work. What am I missing? Thanks for any assistance!
I suppose it is because there is no such column (dproject.school.dname) in #dprojects. You need to join the tables in order to access also the columns of the model School.
I was tested the sorting on a model Book Author, where Book belongs_to :author, pretty similar to your. For the sorting to work I did like what follows:
In controller there is a join table, note the aliases (AS):
sort_by = params[:sort] || 'author_name'
#books = Book.joins(:author).select('books.name AS book_name, authors.name AS author_name').order(sort_by)
I used sort_by to avoid ambiguous column name, as for me there is name column in both models.
Then in view:
<p>id | <%= sortable 'book_name', 'Book' %> | <%= sortable 'author_name', 'Author' %></p>
<% #books.each do |book| %>
<p><%= book.book_name %> | <%= book.author_name %> </p>
<% end %>

publish the nth attribute from a model

I have a model student with a subject and grade attribute. A student can have many subjects and grades, and what I'd like to do is be able to publish the 2nd or 3rd subject listed for a specific student.
For example, the user searches for a student, then clicks on the student, which brings them to a separate page listing information about that particular student (ie, student id:1). Is there code I can add to the view to list the nth item from the subject and grade attributes?
I looked online here and found similar questions, but those solutions related to the model, not the attributes. For example, one solution recommended using the limit method in the controller and another recommended using the following code:
<% firm.state_of_business.split(',').each_with_index do |state, index| %>
<td> <b>State <%= index + 1 %></b> <%= state %>
This seems to work well, when you don't have a specific model selected. When you select a particular model(ie, student id:1), this doesn't seem to work. At least not for me. Right now my code below is showing the first item. How might I get it to list subject 1 & grade 1, subject 2 & grade 2, subject 3 & grade 3, etc.. See sample code below. Please note, that I tried other solutions on here, but couldn't get them to work, which made me think that my problem might be different than the ones previously presented. Thanks for your help.
View Code
<h2>Students</h2>
<p> Student:
<%= #student.name %>
</p>
<table>
<tr>
<th> Subject </th>
<th> Grade </th>
</tr>
<tr>
<td><%= #student.subject %> </td>
<td><%= #student.grade %> </td>
<tr>
</table>
Controller Show Method
def show
#user = current_user
#student = Student.find(params[:id])
end
Desired Output
Student: Matt Jones
Subject Grade
Math 95
History 90
English 91
Try adding this code:
<%= #student.grade.split(',')[0] %>
The [0] will publish the first item in the array. [1] will publish the 2nd item, etc. That should work.
I guess you can just create another model called Subject and add has_many :subjects in class Student.
In class Subject, you can add this line belongs_to :student.
And then you can do this something like this:
<% #student.subjects.each do |subject| %>
<tr>
<td><%= subject.name %> </td>
<td><%= subject.grade %> </td>
<tr>
<% end %>
Just to make it clear, Subject model contains attribute name and grade in above example.

has_many form with nested attributes for existing objects

I am still fairly new to Rails and fairly sure the way I'm attempting to go about this is inefficient or just plain silly, but here's what I'm trying to accomplish. I have 2 models, Cases (patient case files) and Inventories (medical transplant materials used in Cases).
class Case < ActiveRecord::Base
has_many :inventories
accepts_nested_attributes_for :inventories, :reject_if => :all_blank
end
class Inventory < ActiveRecord::Base
belongs_to :case
end
Inventories are created through a separate process and the goal is to associate them with a Case through the Case form. What I am trying to do is put a table on my Case form that lists the available Inventories along with checkboxes to select the desired Inventories to associate with the Case being created. This is further complicated by the fact that I need to be able to include nested fields for a couple of attributes on each Inventory (:case_price and :case_ship_price). I had previously done this in a very roundabout way using a has_many through association and storing those attributes on the pivot table, but it involved some hacky code to capture the field inputs from params and then save them through this block:
class CasesController < ApplicationController
def create
#case = Case.new(params[:case])
if #case.save
#case.case_lineitems.each do |li|
li.update_attributes(:price => params[:lineitem_price][li.inventory_id.to_s],
:shipping_cost => params[:lineitem_shipping][li.inventory_id.to_s])
end
redirect_to #case
else
render 'new'
end
end
end
This felt extremely clumsy and I was worried about problems it might cause, so I wanted to give a simple has_many, belongs_to relationship a try. However, I'm not sure if the typical <%= check_box_tag :inventory_ids, inventory.id, #case.inventories.include?(inventory), name: 'case[inventory_ids][]' %> works for that type of relationship. Here is what this section of my form looks like presently:
<table>
<thead>
<tr>
<th></th>
<th>Product</th>
<th>Serial #</th>
<th>Price</th>
<th>Shipping</th>
</tr>
</thead>
<tbody>
<% #inventories.each do |inventory| %>
<tr>
<td>
<%= check_box_tag :inventory_ids, inventory.id, #case.inventories.include?(inventory), name: 'case[inventory_ids][]' %>
</td>
<td><%= inventory.product.name %></td>
<td><%= inventory.serial_num %></td>
<%= f.fields_for :inventories, inventory do |inv| %>
<td>
<%= inv.text_field :case_price %>
</td>
<td>
<%= inv.text_field :case_ship_price %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
This results in the first checkbox defaulting to checked, and if I leave all unchecked, all of the inventories become associated upon submission. Checking only a subset results in an exception along the lines of Couldn't find Inventory with ID=206 for Case with ID=. Finally, checking all of the Inventories seems to result in the associations and nested attributes saving correctly.
How do I clean this up so that it works as desired? And if I need to go back to a has_many through relationship, is there a better way to save attributes on the pivot table on the same form that creates the row on pivot table? I'd really appreciate any help with this, as no amount of searching has gotten me out of this challenge.

The "Rails" way to submit an unspecified number of user inputs into params

I am working in Rails to allow an administrator to endow fictional money to users. In my mind, there are the following steps:
An administrator asks the DB for a list of users
The administrator specifies the amount of money given to each user
The DB adds the specified amount to each user's account and saves
I have a code that works but is inelegant. I was wondering what the correct "Rails" way to approach this scenario would be. Specifically, I am seeking your help on the following points:
How to elegantly process an indeterminate number of inputs from the user (currently, I generate the form using for loop on all users)
How to send variables used in one action to another (currently, I am using the hidden_field_tag, but I find it a bit cumbersome)
Whether there is a way to avoid calling .to_i, .to_s, .to_f (since it seems quite unnecessary)
How to maximize performance by reducing unnecessary db query
(currently, I am storing the size of users in #size)
My most important questions are #1 and #2. I would appreciate any hint / help. Thank you very much!
#This the action in the controller corresponds to the first bullet point
def index
#users = User.all
#size = #users.length
end
#This the action in the controller corresponds to the third bullet point
def provide_currency
array = *(1..params[:size])
for i in array
user = User.find(i)
user.money += params[i.to_s].to_f
user.save
end
redirect_to admin_path
end
#This is the index.html.erb that corresponds to the second bullet point
<%= form_tag provide_currency_path do %>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>User</th>
<th>E-mail</th>
<th>New endowment</th>
</tr>
</thead>
<tbody>
<% for user in #users %>
<tr>
<td><%= user.name%></td>
<td><%= user.email%></td>
<td>
<%= number_field_tag (user.id) %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= hidden_field_tag "size", #size %>
<%= submit_tag "Provide", :class => "btn" %>
<% end %>

Stop array of strings from saving with dashes

I'm listing the models in my app so an admin can create custom roles:
<% ActiveRecord::Base.send(:subclasses).each do |model| %>
<tr>
<td width=10>
<label><%= check_box_tag "role[read_models][]", model.name, #role.read_models.include?(model.name) %></label><br />
</td>
<td width=10>
<label><%= check_box_tag "role[write_models][]", model.name, #role.write_models.include?(model.name) %></label><br />
</td>
<td><%= model.name %></td>
</tr>
<% end -%>
It works great by the way. In the log it saves the array properly like so:
"read_models"=>["Slug", "Account", "Category", "Document", "Group", "Location", "Role", "Status", "Task", "Ticket"]
But when outputting the results:
<%= #role.read_models.each do |model| %>
<%= model %><br />
<% end -%>
I get this:
---
- Slug
- Account
- Category
- Document
- Group
- Location
- Role
- Status
- Task
- Ticket
(Including the three dashes in the front)
I've tried doing to_a.join(', ') but it still has the dashes in front of each one.
Any ideas on how I need to change this process? Thanks!
I am guessing you have a Role class and this class is the one used to store these values, if this is your case, here's what you could do:
class Role < ActiveRecord::Base
serialize :read_models, Array
end
This will make ActiveRecord store these values you have at the read_models column as a YAML representation (this one you already have) but then you make #role.read_models you will get the Array back and not a string containing the YAML representation.

Resources