This is a simple question but I can't figure out as I am new to rails.
My controller has a #neighborhoods variable which contains neighborhood records for each Business in the #businesses variable (each business has_one neighborhood)
In my view, I want to print out:
Each unique neighborhood name
How many of each unique neighborhood name (can be multiple since it is taken from the #businesses variable)
Currently I have:
<% #neighborhoods.uniq{|x| x.name}.each do |neighborhood| %>
<p><%= neighborhood.name %></p>
<%= #neighborhoods.where{name = neighborhood}.count %>
<% end %>
I know the above code is wrong, but it illustrates what I am trying to do. How can I achieve this?
<% #neighborhoods.group_by(&:name).each do |name, neighbourhoods| %>
<p><%= name %></p>
<%= neighbourhoods.count %>
<% end %>
Related
I have a model called Language, with just two columns: language and link, and would like to be able to loop through each link for each language and display in the view. i.e. (obviously this isn't code, it's just to illustrate the desired pattern)
Language 1
Link 1
Link 2
Link 3
Language 2
Link 1
Language 3
Link 1
Link 2
Language 4
etc
What is the 'rails way' of extracting this data, and then presenting in the view? (note: I would know how to do this easily if the data were in two different models, but it isn't)
So, a Railsy way would be to use the following in your controller:
#languages = Language.all.group_by(&:language)
This will give you a hash of languages grouped by the (erm...) language's language (<- perhaps rename the column to name to avoid this ambiguity?):
# { 'English' => [language_1, language_2, etc...],
# 'French' => [language_3, language_4],
# etc... }
And then this in your view:
<% #languages.each do |language_name, languages| %>
<h1>
<%= language_name %>
</h1>
<% languages.each do |language| %>
<p>
<%= language.link %>
</p>
<% end %>
<% end %>
Obviously the HTML tags can be whatever you'd like, though I hope that gives a useful example.
However, there's a caveat here - as your database grows, this might not prove an efficient way of working. You'll likely be better off setting up a separate model for links, with a one-to-many relationship between languages and links.
For example:
# langage.rb
has_many :links
# link.rb
belongs_to :language
# your controller
#languages = Language.includes(:links)
And then something like the following in the view:
<% #languages.each do |language| %>
<h1>
<%= language.language %>
</h1>
<% language.links.each do |link| %>
<p>
<%= link.url %>
</p>
<% end %>
<% end %>
Working with two models: Casts and Lessons. Cast has many Lessons and Lesson belong to Cast.
I'm trying to loop the content of Lessons within a Cast view with:
<%= #cast.lessons.each do |lesson| %>
<%= lesson.title %>
<% end %>
But the view returns/renders all the attributes of each Lesson instead of just the title.
The equals sign in the loop definition specifies that the output of that line if code should be rendered.
Try this :
<% #cast.lessons.each do |lesson| %>
<%= lesson.title %>
<% end %>
I'm in the process of refactoring some code. I'm trying to use arrays in my view as part of a for loop that makes columns in a table.
I have defined the arrays in my controller:
subjects_controller.rb
def index
...
#CRFS_TO_VIEW = [Baseline, TreatmentCompletion]
#CRF_PATH = {Baseline => 'baseline_path', TreatmentCompletion => tc_path}
end
So my goal; as the function iterates over #CRFS_TO_VIEW, the correct path is selected from #CRF_PATH and appended to the link_to function.
indext.html.erb
<% #CRFS_TO_VIEW.each do |crf| %>
<% path = #CRF_PATH[crf] %>
<%= link_to "edit", path(crf.where(subject_id: sub.subject_id).first %>
<% end %>
I also tried :
<%= link_to "edit", #CRF_PATH[crf](crf.where(subject_id: sub.subject_id).first %>
Which didn't work. I feel I must be getting close, any help or insight would be greatly appreciated.
Thanks.
A few things:
a. You should save yourself some time and loop through the dictionary instead of the array:
<% #CRF_PATH.each do |crf, path| %>
...
<% end %>
b. You are getting a string from the loop - you can invoke the equivalent method with send:
<%= send(path, ...) %>
c. You can simplify your retrieval of the objects using:
crf.find_by(subject_id: sub.subject_id)
That said - this seems like a pretty bad way of doing things. I'd recommend instead adding a view helper:
def crf_path(crf)
case crf
when Baseline then baseline_path(crf)
...
end
With something like this you could use (notice changed the find_by to find_by! for safety as well):
<% #CRFS_TO_VIEW.each do |crf| %>
<%= link_to "edit", crf_path(crf.find_by!(subject_id: sub.subject_id) %>
<% end %>
Finally instance variables should NOT be named upper case. If you want to use a constant define it as a constant (otherwise use lower case names).
I'm new to rails and I'm trying to build a view that will list the parents and related children
Ex:
Passport has many Visas
I want to list information about the passport and the visas that the passport has.
So I have
<% #passport_list.each do |passport| %>
# passportFields
<% passport.visas.each do |visa| %>
<%= t.text_field :visa_type %>
<% end %>
<% end %>
I'm getting the error
undefined method `visa_type' for #Passport:0x000000091b8b28
It looks like rails is trying to find the property visa_type for passport, instead of in visa. How does the scope work within each? Can I force it to access visa_type from visa?
I think you're looking for the fields_for form helper. This will allow you to create fields for the relevant visa attributes. Replace your code sample with the following, and you should be all set.
<% #passport_list.each do |passport| %>
# passportFields
<% t.fields_for :visas do |visa_fields| %>
<%= visa_fields.text_field :visa_type %>
<% end %>
<% end %>
You can also iterate over the list as follows:
<% #passport_list.each do |passport| %>
# passportFields
<% passport.visas.each do |visa| %>
<% t.fields_for :visas do |visa_fields| %>
<%= visa_fields.text_field :visa_type %>
<% end %>
<% end %>
<% end %>
For more information on fields_for, check out the link I added above, and to customize further for your use case, check out the "One-to-many" section.
IMO you should always handle the null case of an object.
Something like this if you use rails (present? is a Rails function)...
<% if #passport_list.present? %>
<% #passport_list.each do |passport| %>
passportFields
<% passport.visas.each do |visa| %>
<%= t.text_field :visa_type %>
<%end%>
<%end%>
<% else %>
<p>Nothing to see here</p>
<% end %>
However if your #passport_list is backed by an ActiveRecord Query, you can handle this in the model/helper/controller by returning the .none query on the model. Note that this differs from an empty array because it is an ActiveRecord Scope, so you can chain AR queries onto it
# scope on AR model
def self.awesomeville
where(country_of_origin: "awesomeville")
end
# method queried in controller
#passport_list = Passport.all
if #passport_list.present?
#passport_list
else
Passport.none
end
# additional filtering in view is now possible without fear of NoMethodError
#passport_list.awesomeville
Whereas a ruby Array would raise an error as it would respond to the Array methods.
I have a Campaign model which has_many Calls, Emails, and Letters.
For now, these are each a separate Model with different controllers and actions (although I would like to start to think of ways to collapse them once the models and actions stabilize).
They do share two attributes at least: :days and :title
I would like a way to represent all the Calls, Emails, and Letters that belong_to a specific Campaign as a sortable collection (sortable by :days), in a way that outputs the model name and the path_to() for each.
For example (I know the below is not correct, but it represents the kind of output/format I've been trying to do:
#campaign_events.each do |campaign_event|
<%= campaign_event.model_name %>
<%= link_to campaign_event.title, #{model_name}_path(campaign_event) %>
end
Thanks so much. BTW, if this matters, I would then want to make the :days attribute editable_in_place.
Here is what I've got working, but want some additional insights
module CampaignsHelper
def campaign_events
return (#campaign.calls + #campaign.emails + #campaign.letters).sort{|a,b| a.days <=> b.days}
end
end
In the VIEW:
<% #campaign_events = campaign_events %>
<% #campaign_events.each do |campaign_event| %>
<% model_name = campaign_event.class.name.tableize.singularize %>
<p>
<%= link_to campaign_event.title, send("#{model_name}_path", campaign_event) %>
<%= campaign_event.days %>
</p>
<% end %>
Like this?
# controller
#campaign = Campaign.find(params[:id])
#campaign_events = (#campaign.calls + #campaign.emails + #campaign.letters).sort{|a,b| a.days <=> b.days}
# view
#campaign_events.each do |campaign_event|
<%= campaign_event.model_name %>
<%= link_to campaign_event.title, #{model_name}_path(campaign_event) %>
end
In controller you find all campaign events and sort it by days field