I have a table and in my code on my html.erb file,
<td class="pstn-column"><%= a.lenders.pluck(:code).join(", ") %></td>
This returns the result in this format
Lender1, Lender2, Lender3
How do i make the result to look like this on the table
Lender1
Lender2
Lender3
I am using rails
Any help appreciated
<% a.lenders.pluck(:code).each do |lender| -%>
<td class="pstn-column"><%= lender %></td>
<% end -%>
I assumed that you need each element in a separate cell.
Just Try this
This code will add br tag after each element
<td class="pstn-column"><%= a.lenders.pluck(:code).join('<br />').html_safe %></td>
or, this will add newline character after each element
<td class="pstn-column"><%= a.lenders.pluck(:code).join("\n") %></td>
Create a new partial and pass the collection to the renderer.
_lender.html.erb
<tr><td><%= lender %></td></tr>
view.html.erb
<%= render #lenders %>
# Or
<%= render partial: 'lender', collection: #lenders %>
controller.rb
#lenders = a.lenders.pluck(:code)
I would make a list of lenders, since that seems to resemble the result you are trying to achieve
<td>
<ul>
<% a.lenders.pluck(:code).each do |lender_code| %>
<li><%= lender_code %></li>
<% end %>
</ul>
</td>
If you want to, the bullets can be removed trough CSS, using <ul style='list-style: none;'>
Related
i want to achieve a nested loop without duplicates in a have and belongs to many relationship
i have a model 'campaign' and for each campaign i also have campaign data.
i want to display each campaign with its campaign data in a table. (nested)
#campaigns = current_user.campaigns
<% #campaigns.each do |item| %>
<% i = item.campaign_data %>
<% i.each do |cdata| %>
<%= cdata.date %>
<tr>
<td>
<%= item.name %>
</td>
<td>
<%= cdata.date %>
</td>
<td>
</td>
</tr>
<% end %>
<% end %>
my problem is that my campaigns get duplicated.
I want to achieve something like this:
Each campaign is listed in the table with its corresponding campaign_data directly below it, and if no campaign_data is left the next loop begins with the next campaign - is this possible?
best regard
You might be getting duplicated campaigns as you are using <%= item.name %> inside the <% i.each do |cdata| %> loop. So, if one campaign has 4 campaign_datas you will see the campaign name 4 times.
You should use naming conventions properly, if the campaign has many data campaign_data then you should specify so in association i.e. has_many :campaign_datas
Also, the Following code should be in the controller
#campaigns = current_user.campaigns.include(:campaign_datas)
Note:- I used include to avoid n + 1, please read here.
In view
<% for campaign in #campaigns %>
<% next if #campaigns.campaign_datas.blank? %>
<tr>
<td><%= item.name %></td>
</tr>
<% for campaign_data in #campaigns.campaign_datas %>
<tr>
<td><%= campaign_data.date %></td>
</tr>
<% end %>
<% end %>
Note:-
<% next if #campaigns.campaign_datas.blank? %> line is used to skip the campaign if it has no campaign data.
So i have this in my view
<% #events.each do |event| %>
<% if event.eventcomplete %>
<% else %>
<tr>
<td colspan="7">
<p>
No Events could be found.
</p>
</td>
</tr>
<% end %>
This is on my search results page,
However what im wanting if there is no eventcomplete, Just display one No events found,
At the moment i'm gettting around 100 events found but, None of them are complete. So i'm getting around 100 "No Events could be found"
Thanks for any help
Sam
I don't know what your code looks like, but something smells wrong to me that you're filtering by eventcomplete in your view both for determining which rows to display and for whether or not to show your "No results" message. Presumably you will later want to do other things using this collection (like pagination), so I'd suggest filtering the collection in the controller:
# controller code
#in_progress_events = #events.where(eventcomplete: false)
Once the collection is being properly filtered before it hits the view, check out the points in this answer for tips on display: Rails: An elegant way to display a message when there are no elements in database
Your code is missing an <% end %> tag.
<% #events.each do |event| %>
<% if event.eventcomplete %>
[insert view code to show if event.eventcomplete is true]
<% else %>
<tr>
<td colspan="7">
<p>
No Events could be found.
</p>
</td>
</tr>
<% end %>
<% end %>
Actually the code is doing exactly what it should do,
your html Block was defined in your each block, this is why it got raised 100 times.
I just fixed it with Helper Variables, but it is just a workaround
You should make use of more static methods in your models, just define it
Please make sure your business logic holds place in your models:
Fat models, Thin Controllers/Views
this should work
<% #there_is_no_eventcomplete = false %>
<% #events.each do |event| %>
<% if event.eventcomplete %>
#there_is_no_eventcomplete = true
<% end %>
<% end %>
<% if #there_is_no_eventcomplete == false %>
<tr>
<td colspan="7">
<p>
No Events could be found.
</p>
</td>
</tr>
<% end %>
You want to use a scope on your model which you can then call in the controller. I'm not sure how you've set up your model or how you determine if an event is completed, so lets assume you have a boolean attribute completed on your model:
event.rb
class Event
def self.completed
where(complete: false)
end
end
controller
#events = Event.completed
view
<% unless #events.nil?
<% #events.each do |event|%>
// your code
<% end %>
<% else %>
// your code
<% end %>
For a current project, I have duplicate code between views, and I'm not sure of the best route to refactor it.
I appear to be in a position where I can have duplicate code across various .html.erb files, or I could put identical code into a partial and use conditionals. I've always heard logic should stay out of views. Neither option seems ideal, and I don't currently know of alternatives.
To illustrate my question, I created a simple rails app called animals. I scaffolded for two models: one for cat and one for dog. Images display their corresponding attributes:
Displaying #cats and #dogs is pretty much the same. Cats just have a column for meows while Dogs have a column for barks, and a dog has the additional attribute column of plays_catch.
Lets say we choose to reduce the duplicate code for displaying cats and dogs by making a shared view partial:
#views/shared/_animal.html.erb
<tr>
<td><%= animal.name %></td>
<td><%= animal.age %> </td>
<% if animal.class == Cat %>
<td><%= animal.meows %> </td>
<% end %>
<% if animal.class == Dog %>
<td><%= animal.barks %> </td>
<td><%= animal.plays_catch %> </td>
<% end %>
</tr>
Then to render #cats = Cat.all:
<%= render partial: "shared/animal", collection: #cats %>
Then to render #dogs = Dog.all:
<%= render partial: "shared/animal", collection: #dogs %>
Obviously it would be overkill to do something like this for this specific example, but the real world project I'm applying it to would not be overkill.
The overall question is: how do you remove nearly identical code that iterates over collections, where the only difference is adding/removing a column of information? It just doesn't feel right to put that logic in the view itself, and leaving the duplication feels wrong.
You could use decorators and add methods that return the extra column(s):
class DogDecorator < Draper::Decorator
def extra_columns
[:barks, plays_catch]
end
end
class CatDecorator < Draper::Decorator
def extra_columns
[:meows]
end
end
...
<% animal.extra_columns.each do |column| %>
<td><%= animal.attributes[column.to_s] %>
<% end %>
...
<% #cats = CatDecorator.decorate_collection(Cat.all)
<%= render partial: "shared/animal", collection: #cats %>
You can use respond_to? to solve the problem more generically. The view logic doesn't feel so wrong when it's more generic.
<% [:meows, :barks, :plays_catch].each do |method| %>
<% if animal.respond_to?(method) %>
<td><%= animal.send(method) %> </td>
<% end %>
<% end %>
You can add a method of the same name to both Cat and Dog classes which would return the specific instance attributes names and values. I'd recommend returning two arrays (one with the names of the fields, other with the fields' values, or vice-versa) since hashes are not exactly ordered. This way you can control the order in which they'll appear in the view.
For example:
#models/cat.rb
def fields_and_attributes
fields = ["Name","Age","Meows"]
attributes = [self.name, self.age]
if self.meows
attributes.push("Yes")
else
attributes.push("No")
end
[fields,attributes] # make sure each attribute is positioned in the same index of its corresponding field
end
#models/dog.rb
def fields_and_attributes
fields = ["Name","Age","Plays catch"]
attributes = [self.name, self.age]
if self.plays_catch
attributes.push("Yes")
else
attributes.push("No")
end
[fields,attributes] # make sure each attribute is positioned in the same index of its corresponding field
end
#controllers/animals_controller.rb
def display_animals
#animals = Cat.all + Dog.all # an array containing the different animals
end
#views/display_animals.html.erb
for i in (0...#animals.size)
fields_and_attributes = #animals[i].fields_and_attributes
for f in (0...fields_and_attributes[0].size)
<p><%= fields_and_attributes[0][f] %> : <%= fields_and_attributes[1][f] %></p>
end
end
Here, we first iterate over all of the animals and call the .fields_and_attributes method of that specific record; we then iterate over the results of calling that method, displaying fields and attributes in the same order as the one defined within the method and also guaranteeing that the code will display every field and every attribute regardless of the difference in the total number of fields for each different animal.
I don't know of any canonical way to accomplish this, but I would use one partial for this in the following way:
<tr>
<% animal.attributes.each do |_, value| %>
<td><%= value %></td>
<% end %>
</tr>
You can get rid of repeated attributes calls by providing in the partial a local variable with pre-obtained model attributes.
EDIT: if you only want to display some attributes.
# Declare whitelist of attributes
# (you can also declare a blacklist and just calculate the difference between two array: all_attributes - blacklist_attributes):
<% whitelist = [:name, :age, :barks] %>
<%= render partial: 'shared/animal',
collection: #dogs,
locals: {attrs: (#dogs.first.attributes.keys.map(&:to_sym) & whitelist)} %>
views/shared/_animal.html.erb:
<tr>
<% attrs.each do |attr| %>
<td><%= animal[attr] %></td>
<% end %>
</tr>
Below is my answer after reviewing posted answers. Basically:
I left the differences within each scaffold model's index page
I made shared partials for common table headers and table data
code below:
#app/views/cats/index.html.erb
<h1>Listing Cats</h1>
<table>
<thead>
<tr>
<%= render partial: "shared/cat_dog_table_headers" %>
<th>Meows</th>
</tr>
</thead>
<tbody>
<% #cats.each do |cat| %>
<tr>
<%= render partial: "shared/cat_dog_table_data", locals: {animal: cat} %>
<td><%= cat.meows %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Cat', new_cat_path %>
And for the dogs:
#app/views/dogs/index.html.erb
<h1>Listing Dogs</h1>
<table>
<thead>
<tr>
<%= render partial: "shared/cat_dog_table_headers" %>
<th>Barks</th>
<th>Plays catch</th>
</tr>
</thead>
<tbody>
<% #dogs.each do |dog| %>
<tr>
<%= render partial: "shared/cat_dog_table_data", locals: {animal: dog} %>
<td><%= dog.barks %></td>
<td><%= dog.plays_catch %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Dog', new_dog_path %>
The shared table headers for cats and dogs:
#app/views/shared/_cat_dog_table_headers
<td><%= Name %></td>
<td><%= Age %></td>
The shared table data for cats and dogs:
#app/views/shared/_cat_dog_table_data_headers
<td><%= animal.name %></td>
<td><%= animal.age %></td>
This question already has answers here:
Rails: An elegant way to display a message when there are no elements in database
(10 answers)
Closed 8 years ago.
I'm a newbie at Rails and I'm having trouble wrapping my head around refactoring logic from views. Let's say I have a simple Post model. In the index view, I want specific content to be displayed if there are posts or not. Basically, if there are any posts, display this specific content or else this other content.
Here is my index.html.erb view for Posts:
<div class="content">
<% if #posts.any? %>
<table>
<thead>
<tr>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.content %></td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p>There are no posts!</p>
<% end %>
</div>
Now, the way I refactored this was by creating a couple of helpers and partials like so:
posts_helper.rb (which renders the partials according to the if logic):
module PostsHelper
def posts_any
if #posts.any?
render 'this_content'
else
render 'this_other_content'
end
end
end
In the partials, I just used the exact content in the if else statement.
_this_content.html.erb partial:
<table>
<thead>
<tr>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.content %></td>
</tr>
<% end %>
</tbody>
</table>
_this_other_content.html.erb partial:
<p>There are no posts!</p>
Finally, the refactored index.html.erb (which would call the helper method):
<div class="content">
<%= posts_any %>
</div>
The problem is, I'm just not convinced that this is the correct Rails way of refactoring. If any of you could shed some light on this, I would highly appreciate it!
Thanks!
You're doing it right, and better than many people I know. :)
A few minor adjustments...
I would move the render from the helper to the erb, and just use the helper to return the right name of what to render.
Your erb code and helper code:
<%= posts_any %>
def posts_any
if #posts.any?
render 'this_content'
else
render 'this_other_content'
end
end
I suggest:
<%= render posts_any %>
def posts_any
#posts.any? ? 'this_content' : 'this_other_content'
end
Next, I personally like to render a collection using a partial.
Yours:
<% #posts.each do |post| %>
I suggest:
<%= render partial: "post", collection: #posts %>
And in the comment below, user kyledecot suggests even terser:
<%= render #posts %>
Then create the file _post.html.erb like this:
<tr>
<td><%= post.title %></td>
<td><%= post.content %></td>
</tr>
Some developers think that it's overkill to render a collection using a partial, in the case where the partial is not used anywhere else.
I personally think it's helpful, and especially useful when a project has multiple coders some of whom may be changing the table row data results.
I have created a scaffold Phone and index.html.erb shows a simple table with list of phone and edit/delete options. Now i want to add jquery checkboxes so I can do bulk delete or move actions. See attached image here
Can someone give me any idea/pointers on how to do it ?
Edit - this is the index.html.erb file
<% #phones.each do |phone| %>
<tr>
<td><%= phone.model %></td -->
<td><%= phone.type %></td>
</tr>
<% end %>
there is no form here so I am not sure I can use form_tag helpers or am I confusing something ?
Thanks
This would be a starting point, a form with the check boxes.
<%= form_tag(:controller => "phone", :action => "bulk_update", :method => "PUT") %>
<%= check_box_tag(:blackberry) %>
<%= label_tag(:pet_dog, "Blackberry") %>
<%= check_box_tag(:Nokia) %>
<%= label_tag(:pet_cat, "Nokia") %>
<%= submit_tag("Update") %>
<% end %>
Then a controller action called bulk_update and you could delete/update the records based on what has been submitted.
EDIT: You will also want to create a route in routes.rb for this.
Wrap the table in a form helper.
<%= form_tag foo_path do %>
# ...
<% #phones.each do |phone| %>
<tr>
<td><%= check_box_tag "selected[]", phone.id %></td>
<td><%= phone.model %></td>
<td><%= phone.type %></td>
</tr>
<% end %>
# ...
<%= button_tag "Do something" %>
<% end %>
This creates a form, with a checkbox in every row of the table. Replace foo_path with the route helper that you want to use. The value of the selected checkboxes will be passed to your controller action in the array params[:selected], where you can do with them as you wish. The values of each checkbox will be the id for the corresponding phone object.