How to move instance_method with args from view? - ruby-on-rails

I have following line code in my view:
<td> Model.some_instance_method(args) </td>
I would like to clear this. Below i paste whole code.
https://gist.github.com/3039144

You don't make it super clear as to what your objective is. Assuming you just want it to be more idiomatic rails code, something like this would be much cleaner:
class PinnedContent < ActiveRecord::Base
def reports
PinnedContentReport.where("pinned_content_id = ?", self.id).count
end
end
In your view:
<% #reported_pinned_contents.each do |reported_pinned_content| %>
<tr>
<td><%= reported_pinned_content.id %></td>
<td><%= reported_pinned_content.reports %></td>
<td></td>
</tr>
<% end %>

Related

Active record is not display table

As working on the Active Record as i have work on different function for active reocrd like Avg, sum and count as it display working fine and also Chart,
but one things is baffle me and i still cannot get it working and it should be working fine, as i cannot get display all data list table like
<table id="dttb" class="table table-hover">
<thead>
<tr>
<th> full name </th>
</tr>
</thead>
<tbody>
<tbody>
<% #user.each do |user| %>
<tr>
<td><%= user.fullname %></td>
</tr>
<% end %>
</tbody>
</tbody>
</table>
as it should be working as the error is kept displayed
undefined method `each' for nil:NilClass
as I look up information and most of them are mention .each do, seems I am doing wrong as I have used
<%= User.count(:user) %>
and
<%= column_chart User.group(:provider).count(:user) %>
and it seems working fine as query function.
so I tried again with find_each
<% User.find_each do |user| %>
<tr>
<td><%= puts user.fullname %></td>
</tr>
<% end %>
and the error is gone but it does not display at the data and it's show blanks unless I put 'link_to' but they keep display like
and I have put on AdminController.rb
class AdminController < ApplicationController
before_action :authenticate_user!
def index
#user = User.all
#tools = Tool.all
end
end
seems I miss something, I have look google or stackover flow, most of them answer are very same as this code as I wrote
Update: as I am able to get some data like a phone number or email
Here is code i wrote
<% User.find_each do |user| %>
<tr>
<td><%= link_to user.id, user %></td>
<td><%= link_to user.email, user %></td>
<td><%= link_to user.created_at.strftime('%v'), user %></td>
<td><%= link_to user.fullname, user %></td>
<td><%= link_to user.phone_number, user %></td>
</tr>
<% end %>
but frustration with fullname as it should be displayed but it not
Set #user (or better #users) in the controller:
def index # or the actual action name
#users = User.all # or User.order(:fullname)
end

Displaying has and belongs to many associations in index

Hey I'm new to Rails and all this so bear with me, thanks!
I have two models:
class User < ApplicationRecord
has_and_belongs_to_many :sports
end
class Sport < ApplicationRecord
has_and_belongs_to_many :users
end
My users have a few different sports that they can choose each. I'm simply trying to display all users in a table, along with which sports they do. However.. the only way I've managed to get anything without an error is by using current_user as shown below. I've been looking how to do this for hours... I know it's going to be stupidly simple but I just can't figure it out or even know how to go in the right direction.
# users_controller.rb
def index
#users = User.all
#sports = current_user.sports
end
# users/index.html.erb
<% #users.each do |user| %>
<tr>
<td><%= link_to user.name, user %></td>
<td><%= link_to user.email, user %></td>
<% #sports.each do |s| %>
<td><%= s.name %></td>
<% end %>
</tr>
<% end %>
That's my current code but obviously this shows only the signed in users associations and repeats it for the other users like this:
<table>
<tr>
<th>Name</th>
<th>Sport 1:</th>
<th>2:</th>
</tr>
<tr>
<td>User 1 (current_user)</td>
<td>Football</td>
<td>Running</td>
</tr>
<tr>
<td>User 2</td>
<td>Football (User 1's Sports)</td>
<td>Running </td>
</tr>
</table>
Thanks in advance.
You can try using the following and deleting #sports = current_user.sports:
<% user.sports.each do |s| %>
<td><%= s.name %></td>
<% end %>
using user.sports while looping through each of the user will lead to N+1 queries on your database. You can change your controller method to something like
def index
#users = User.all.eager_load(:sports)
end
and then in html
<% user.sports.each do |s| %>
<td><%= s.name %></td>
<% end %>
This will load users along with left_outer_join on sports table and this will save to lot of extra queries on your database.
For Info you can refer this good blog.
Thanks

Calling a helper method in view dynamically during loop with ruby on rails

<table>
<tr>
<th>Player Name</th>
<th>Club</th>
<th>Position</th>
<th>Points</th>
<th>Price</th>
</tr>
<% #myteam.each do |p| %>
<% #pd = playerDetails(p) %>
<tr>
<td><%= #pd.club %></td>
<td><%= #pd.name %></td>
<td><button>Remove</button></td>
</tr>
<% end %>
</table>
In the above I'm trying to get the players from myteam and put each in p. This works, I'm then trying to call a method on p called playerDetails and assign the values to #pd. This doesn't seem to work. Anyone know where exactly I've gone wrong? I only started learning ruby on rails today.
This is the playerDetails method by the way:
def playerDetails(pid)
#pd = Player.where(:id => pid)
end
helper_method :playerDetails
#pd will be an array. Try this
#pd = Player.where(:id => pid).first
A suggestion - You may want to fill the #myteam array with Player instances instead of player ids. It's faster to query for all the objects at once.

Rails 3 each do ignore nil values

I am building an html table that should include name, rating1, rating2, and rating3. rating 1-3 come from different models than name.
resources :names do
resource :rat1,:rat2,:rat3
end
Inside of my html table I'd like to include the ratings from within each of these tables but I would like to automatically skip over or ignore tables that are nil. This is because :names may only have a :rat1 and not a :rat2 or :rat3. My view should look something like this.
<table>
<thead>Name</thead>
<thead>Rating 1</thead>
<thead>Rating 2</thead>
<thead>Rating 3</thead>
<% #names.each do |name| %>
<tr>
<td><%= name.nametext %></td>
<td><%= name.rat1.rating %></td>
<td><%= name.rat2.rating %></td>
<td><%= name.rat3.rating %></td>
</tr>
<% end %>
</table>
Except that if name.rat1 is nil it will either a.) replace the value with N/A OR b.) it will leave this field blank and move on to the next.
What is the cleanest way to do this?
::UPDATE::
So my issue is that the name.rat1 is nil and the name.rat1.rating is an undefined method of a nil class so both of these options will throw the same undefined method of a nil class error regardless of the || or helper method. At least thats what my current tests are showing. Any other options? or different workarounds? I'd like to avoid having to put a validation loop like this for every rat1-3
<% unless name.rat1.nil? %>
<%= name.rat1.rating %>
<% end %>
There has to be a simpler way.
I would probably create a helper method in names_helper.rb
def show_rating(rating)
if rating.present?
rating
else
"default value"
end
end
Then use it in the view:
<%= show_rating name.rat1.rating %>
OFFTOPIC Your table structure is wrong. It should have <thead><tr><th>Name</th><th>Rating1</th>..so on..</tr></thead>
So, in your case you can use the condition while rendering the rating values as:
<table>
<thead>
<tr>
<th>Name</th>
<th>Rating 1</th>
<th>Rating 2</th>
<th>Rating 3</th>
</tr>
</thead>
<tbody>
<% #names.each do |name| %>
<tr>
<td><%= name.nametext %></td>
<td><%= name.rat1.rating || 'N/A' %></td>
<td><%= name.rat2.rating || 'N/A' %></td>
<td><%= name.rat3.rating || 'N/A' %></td>
</tr>
<% end %>
</tbody>
</table>

DRY in Rails 3 if else elsif

Second week on RoR (with no programming background). And I have a bit of an issue, I'm doing a Metacritic type of a website. And there are going to be ratings everywhere. I decided on 0 to 33 = red 34 to 66 = orange 67 to 100 = green which looks like that
index (controller:show)
<td><% if show.reviews.count == 0 %>0
<% elsif show.reviews.average("rating").between?(33, 66) %>
<table class="orange">
<tr>
<td><b><%= number_with_precision(show.reviews.average("rating"), :precision => 0) %></b></td>
</tr>
</table>
<% elsif show.reviews.average("rating").between?(66, 100) %>
<table class="green">
<tr>
<td><%= number_with_precision(show.reviews.average("rating"), :precision => 0) %></td>
</tr>
</table>
<% elsif show.reviews.average("rating").between?(00, 33) %>
<table class="red">
<tr>
<td><%= number_with_precision(show.reviews.average("rating"), :precision => 0) %></td>
</tr>
</table>
<% end %>
</td>
My issue is that I'm gonna need to repeat that code, a lot, see (I'm only getting started:
show (controller show)
<p>
Note: <% if #ratings == 0 %>0
<% elsif #ratings.between?(33, 66) %>
<table class="orange">
<tr>
<td><b><%= number_with_precision(#ratings, :precision => 0) %></b></td>
</tr>
</table>
<% elsif #ratings.between?(66, 100) %>
<table class="green">
<tr>
<td><%= number_with_precision(#ratings, :precision => 0) %></td>
</tr>
</table>
<% elsif #ratings.between?(00, 33) %>
<table class="red">
<tr>
<td><%= number_with_precision(#ratings, :precision => 0) %></td>
</tr>
</table>
<% end %>
</p>
Somebody told me this should be a model but I don't really know how to write it. Any help ?
First of all you should add an instance method to your Show model that retrieves and caches the average rating for a show. This prevents querying the database multiple times for the same data:
def average_rating
#average_rating ||= self.reviews.average('rating')
end
The code that returns the appropriate css class for a Show can go into a helper (e.g. the ShowHelper):
module ShowHelper
def average_rating_class_for(show)
if show.average_rating < 34
'red'
elsif show.average_rating > 66
'green'
else
'orange'
end
end
end
With this, your views become much cleaner:
<td>
<% if show.reviews.count == 0 %>
0
<% else %>
<table class="<%= average_rating_class_for(show) %>">
<tr>
<td><%= number_with_precision(show.average_rating, :precision => 0) %></td>
</tr>
</table>
<% end %>
</td>
And:
<p>
Note:
<% if #show.reviews.count == 0 %>
0
<% else %>
<table class="<%= average_rating_class_for(#show) %>">
<tr>
<td><%= number_with_precision(#show.average_rating, :precision => 0) %></td>
</tr>
</table>
<% end %>
</p>
You could even move the generation of the entire table into a model. (Although you shouldn't be using a table here, but that's a different matter.)
module ShowHelper
def average_rating_class_for(show)
if show.average_rating < 34
'red'
elsif show.average_rating > 66
'green'
else
'orange'
end
end
def average_rating_table_for(show)
if show.reviews.count == 0
'0'
else
content_tag :table do
content_tag :tr do
contect_tag :td, :class => average_rating_class_for(show) do
number_with_precision(show.average_rating, :precision => 0)
end
end
end
end
end
end
With this you view becomes:
<td>
<%= average_rating_table_for(show) %>
</td>
What Andre suggests is possible too, but it may be a bit difficult to comprehend for a beginner like yourself. This is simpler.
You will need to make a new folder in your app directory called presenters.
Then you will want to create a file called rating_presenter.rb
This will be your presenter file
class RatingPresenter
def initialize(rating, template)
#rating = rating
#template = template
end
def get_ratings
# here you will house the logic to display your tables as needed
# I would probably determine the output to return the class to set the table accordingly
# keep in mind that view helpers are available
# ie. h.link_to or h.form_tag
end
private
def h # we don't want to be saying #template.link_to etc everywhere, so this is a shortcut
#template
end
end
And in the application_helper.rb file
We need to determine the class in order to present the class
def present(object, klass = nil)
klass ||= "#{object.class}Presenter".constantize # assign object or nil
presenter = klass.new(object, self) # assign presenter to object instance
yield presenter if block_given? # yield if block is given
presenter # return presenter
end
So in your view
You call the helper method that is then
<% present #rating do |rating_presenter| %>
<p>
<%= rating_presenter.get_ratings %>
</p>
<% end %>
So this is a quick and dirty example from a couple resources I've learned. You will need to experiment/break stuff a bit to have it suit your needs. You can expand on the get_ratings method and use more than one method to build your table ( this is recommended ) instead of having one method be responsible for the whole thing. It will help you to isolate problems. Hope this points you in the right direction
You should also search on google for "presenters +rails", you may find some more articles that will further help you understand this concept. Finally rails has gems for handling complex view logic, check out Draper. https://github.com/drapergem/draper
I think for somebody "Second week on RoR (with no programming background)" using a presenter is a little out of scope. Also one should try and simplyfy step by step and only to the level one is comfortable with (no use in using constructs one does not understand)
My advise would be to simply write a small helper to decide which colour the div should be. As a first shot simply put the following method into app/helpers/application_helper.rb
def color_for_rating(rating)
if show.average_rating < 34
'red'
elsif show.average_rating > 66
'green'
else
'orange'
end
end
you could then clean up your index view as following by using the helper to give the correct colour for your table class
<td><% if show.reviews.count == 0 %>0
<% else %>
<table class="<%= color_for_rating(show.reviews.average("rating")) %>" >
<tr>
<td><b><%= number_with_precision(show.reviews.average("rating"), :precision => 0) %></b></td>
</tr>
</table>
<% end %>
</td>
As soon as you feel comfortable with this easier approach and have used it a little you can check back to investigate the more advanced solutions given in the other answers.

Resources