I'm learning RoR and I'm trying to understand associations. I've got two models - Company [name] and Note [company_id, notes]. As shown, the Note model has a company_id field to reference the primary key in the Company model.
Within a Notes view, I'm trying to display the Company name but I can't seem to get this to work.
I want to display
(SELECT name FROM Company WHERE Company.id=Note.company_id)
instead of note.company_id in the code below.
company.rb
class Company < ActiveRecord::Base
has_many :notes
end
note.rb:
class Note < ActiveRecord::Base
belongs_to :company
default_scope -> { order(date: :desc) }
end
notes/index.html.erb
....
<% #notes.each do |note| %>
<% if note.active %>
<p>
<%= note.date %>
</br>
<%= note.company_id %> - <%= note.contact %>
</br>
<%= note.notes %>
<!-- <td><%= note.active %></td> -->
</p>
<% end %>
<% end %>
....
To answer your specific question, try:
note.company.name
I would also recommend reading up on Rails partials, particularly how to render a collection: http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
Related
First, the example I read in the docs shows to declare the associated model as singular, :address, but if I do I get the error Association named 'address' was not found on User; If I change it to plural :addresses, then the next problem I have is the association doesn't work in views undefined method `country' for ...
Why am I declaring the association as plural and how can I make the association available in the view
User.rb:
class User < ActiveRecord::Base
searchkick word_middle: ['full_name', 'description', 'interests']
has_many :addresses
scope :search_import, -> { includes(:addresses) }
search.html.erb:
<% #users.each do |u| %>
<li>
<%= link_to "#{u.first_name} #{u.middle_name} #{u.last_name}", page_path(name: u.name) %>
<% #ua=u.addresses.where("current=?", true) %>
<% if #ua.country=="US" %>
<%= #ua.city %>, <%= #ua.state %> <%= ISO3166::Country.find_country_by_alpha2(#ua.country) %>
<% else %>
<%= #ua.city %>, <%= ISO3166::Country.find_country_by_alpha2(#ua.country) %>
<% end %>
</li>
<% end %>
</ul>
In controller, do this: #user = User.includes(:addresses).where(your_query) to make the association readily available in view.
And yes has_many associations are bound to be plural: "User has_one
:life" and "User has_many :passions"; does it make sense?
And finally your error: where returns an array because you queried: "bring me all records which fulfill this condition". find, on the other hand, will bring back 1 specific record as it expects a unique attribute or brings back first record that matches that attribute.
What you need to do:
You should either do this (if you are dead-sure that you will get 1
such record or you need only one of that type):
<% #ua=u.addresses.where("current=?", true).first %>
OR
If you need to go through all the resultant array then:
<% #ua=u.addresses.where("current=?", true) %>
<% #ua.each do |ua| %>
# Your code for each ua instead of #ua.
<% end %>
Happy Learning :)
I am working on an application a deep association. A Story belongs to a Planning Level, the Planning Level belongs to one or many Programs.
class Program < ActiveRecord::Base
has_and_belongs_to_many :planning_levels
has_many :stories, :through => :planning_levels
end
class PlanningLevelsPrograms < ActiveRecord::Base
end
class PlanningLevel < ActiveRecord::Base
has_and_belongs_to_many :programs
has_many :stories
end
class Story < ActiveRecord::Base
belongs_to :planning_level
end
Within the Program show page I'd like to display the Program, each Planning Level and aggregate Story count for each Planning Level.
I'm not sure how to access the Story model from the Program show page.
The following works great for displaying each Planning Level belonging to the Program.
<% #program.planning_levels.each do |p| %>
<p><%= p.name %></p>
<% end %>
...but I have no idea how to make the following work for each displayed Planning Level. How do I access the Story model from with the Program? Is there something needed in the Program controller that I'm missing. Thanks in advance!
#program.planning_level.stories.count(:id)
Each Planning Level:
<% #program.planning_levels.each do |planning_level| %>
<p><%= planning_level.name %></p>
# Aggregate Story count for each planning_level
<p><%= planning_level.stories.count %></p>
<% end %>
Aggregate Story count for #program (if you want):
#program.stories.count
Hope this can help you.
In your view, you can simply use the model associations by name to do this. Try this code as a starting point for your display needs:
<% #program.planning_levels.each do |planning_level| %>
<p><%= planning_level.name %> with <%= planning_level.stories.count %> stories</p>
<% planning_level.stories.each do |story| %>
<p><%= story.name %></p>
<% end %>
<% end %>
You can output any details that you choose for the stories loop. You can add styling to get the presentation that you need.
For instance, you might consider formatting this as a nested list, like so:
<% #program.planning_levels.each do |planning_level| %>
<ul>
<li>Planning Level: <%= planning_level.name %> with <%= planning_level.stories.count %> stories
<ul>
<% planning_level.stories.each do |story| %>
<li>Story: <%= story.name %></li>
<% end %>
</ul>
</li>
</ul>
<% end %>
Adding CSS class and id attributes would give you the ability to add styling to the elements to give your UI some flair.
I'm creating an app that has two sets of content that's unrelated.
The first is Questions and Answers (Q&As) where a user can ask a question and the community can answer.
The second is an RSS like feed where an article is posted and links to a 3rd party site.
I'd like to create a 'Feed' so when the user logs in, they see the latest of the Q&As and the latest news all mixed together. I've got it working now where they aren't mixed together.
So two questions, how do i combine the two data sets? And what is the code to make it viewed given it's different content in each table.
Here is my code:
app>models>feed.rb
class Feed < ActiveRecord::Base
validates :name, :url, :description, :source, presence: true
end
app>models>question.rb
class Feed < ActiveRecord::Base
belongs_to :user
has_many :answers, dependent: :destroy, foreign_key: "id"
end
app>controllers>feeds_controller.rb
def index
#feeds = Feed.where("created_at >= ?", Date.today)
#questions = Question.where("created_at >= ?", Date.today)
end
app>views>feeds>index.html.erb
<% #feeds.each do |feed| %>
<h3><%= feed.name %></h3>
<p><%= feed.source %></p>
<p> <%= feed.created_at.strftime("%b %d, %Y") %> </p>
<%= link_to image_tag(feed.image.url(:medium)), feed.url %><br>
<%= truncate(feed.description, length: 50) %><br>
<% end %>
<% #questions.each do |question| %>
<tr>
<td><h1><%= link_to question.question , question_path(question) %></h1></td>
<td><p>Posted by: <%= question.user.name %></p></td>
<td> <p><%= question.created_at.strftime("%b %d, %Y") %> </p></td>
<td><p>Number of answers: <%= question.answers.count %> </p></td>
</tr>
<% end %>
I don't think join works given they have different data. Any suggestions on how to combine feed and questions into one stream with the most recent at the top? (like a facebook feed).
thanks for your help!
I'd suggest this... which is doing array sorting, but I think you don't have a choice with two unrelated object types.
#combined = (#feeds.to_a + #questions.to_a).sort{|a,b| b.created_at <=> a.created_at}
Then in the view...
<% #combined.each do |combined| %>
<%= render combined %>
<% end %>
The beauty of the render is that it will render a partial appropriate to the type of object. If combined s a Feed object the partial used will be feeds/_feed but if it's a Question object it will use the partial questions/_question
I was able to get this working with a few small changes. Rather than rendering the partial I did the following
<% #combined.each do |combined| %>
<% if combined.is_a?(Feed) %>
<h3><%= combined.name %></h3>
<p><%= combined.source %></p
...
<% else %>
<% end %>
Thank you for your help!
Here is my structure:
Villa model with a belong_to association with a destination model (destination_id).
User model with a habtm association with destination model.
Today in my index view, I use :
<% current_user.destinations.each do |destination| %>
<% #villas.each do |villa| %>
<% if destination == villa.destination %>
<%= villa.name %>
<%end%>
<%end%>
<%end%>
It's not very clear, so can I make a kind of scope in my villa model to select Villas where destination_id == current_user.destinations ?
Thanks a lot
Why don't you list the children villas from the destination itself?
<% current_user.destinations.each do |destination| %>
<% destination.villas.each do |villa| %>
<%= villa.name %>
<%end%>
<%end%>
If you want to forgo this built-in functionality, or if you're scoping a query further from your #villas relation, here's how you do the scope as per these docs
class Villa < ActiveRecord::Base
# ...
scope :by_destinations, -> (destinations) { where(destination: destinations) }
# alternatively...
def self.by_destinations(destinations)
where(destination: destinations)
end
end
Then refer to it with
<% #villas.by_destinations(current_user.destinations) do |villa| %>
<%= villa.name %>
<%end%>
I'm getting the above error when I submit my nested form and I'm not sure how to fix it. Here is some info. The exact error is No route matches [POST] "/vehicles/2/vehicle_records/new". The strange thing is that route is present when I run rake routes I see the following entry
/vehicles/:vehicle_id/vehicle_records/new(.:format)
vehicle.rb
class Vehicle < ActiveRecord::Base
has_many :vehicle_records, dependent: :destroy
accepts_nested_attributes_for :vehicle_records
end
vehicle_record.rb
class VehicleRecord < ActiveRecord::Base
belongs_to :vehicle
end
I want the ability to add a vehicle maintenance record linked from the vehicle show view.
views/vehicle/show.html.erb
<h3><b>Vehicle ID:</b> <%= #vehicle.id %></h3>
<p><b>Year:</b> <%= #vehicle.year %></p>
<p><b>Make:</b> <%= #vehicle.make %></p>
<p><b>Model:</b> <%= #vehicle.model %></p>
<p><b>Work Last Performed:</b> <%= #vehicle.make %></p>
<h2>Maintenance Record</h2>
<table>
<tr>
<th>Date Performed</th>
<th>Mileage</th>
<th>Hours</th>
<th>Work Performed</th>
</tr>
<% #vehicle.vehicle_records.each do |vr|%>
<tr>
<td><%= vr.date_performed %></td>
<td><%= vr.mileage %></td>
<td><%= vr.hours %></td>
<td><%= vr.work_performed %></td>
</tr>
<% end %>
</table>
<%= link_to "Add Maintenance Record", new_vehicle_vehicle_record_path(#vehicle) %>
I then link to the vehicle_record new form
views/vehicle_records/new.html.erb
<%= form_for :vehicle_record do |vr| %>
<p>
<%= vr.label :date_performed%><br />
<%= vr.text_field :date_performed%>
</p>
<p>
<%= vr.label :mileage%><br />
<%= vr.text_field :mileage%>
</p>
<p>
<%= vr.label :mileage%><br />
<%= vr.text_field :mileage%>
</p>
<p>
<%= vr.label :hours%><br />
<%= vr.text_field :hours%>
</p>
<p>
<%= vr.label :work_performed%><br />
<%= vr.text_area :work_performed%>
</p>
<p><%= vr.submit "Create Record" %></p>
My vehicle records controller is as follows
vehicle_records_controller.rb
class VehicleRecordsController < ApplicationController
def new
#vehicle_record = VehicleRecord.new
end
def create
#vehicle_record = VehicleRecord.new(params[:vehicle_record])
if #vehicle_record.save
redirect_to vehicles_path
else
flash[:notice] = "Not Saved"
end
end
end
routes.rb
resources :vehicles do
resources :vehicle_records
end
Update: w/o nested forms
So I hear you only want to only edit the vehicle_report without touching the vehicle. Since you already have your vehicle_report as nested resource, you can modify your controller as follows:
class VehicleRecordController < ApplicationController
...
def new
#vehicle = Vehicle.find params[:vehicle_id]
#vehicle_record = #vehicle.vehicle_records.build
end
...
end
and the content of create method is fairly easy. Then you have to change your form to:
<%= form_for #vehicle_record do |v| %>
...
<%= # vehicle record attributes %>
...
<%= v.submit "Submit" %>
And you are good to go!
Original answer: w/ nested forms
First of all, I don't see you using any nested forms. Second, I don't see how your vehicle_record form gets to know to which vehicle it actually belongs (see your controller). In my opinion the simplest way would be to allow adding and removing of vehicle_records directly in vehicles/:id/edit or vehicles/new using nested forms:
<%= form_for #vehicle do |v| %>
...
<%= # vehicle attributes here %>
...
<%= v.fields_for :vehicle_records do |vr| %>
...
<%= # vehicle record attributes %>
...
<%= v.submit "Submit" %>
For existing vehicles the fields_for will render list of all existing vehicle_records and for new ones your can have the following code in your controller to make fields_for render for example three empty vehicle_records:
class VehicleController < ApplicationController
...
def new
#vehicle = new Vehicle
3.times { #vehicle.vehicle_records.build }
end
...
end
If you want to always have a number of free vehicle_records every time you edit an existing vehicle you can use a similar approach for your edit and reuse the aforementioned form:
class VehicleController < ApplicationController
...
def edit
#vehicle = Vehicle.find params[:id]
# Add one blank vehicle record to existing ones
# This is also rendered by fields_for
#vehicle.vehicle_records.build
end
...
end