Test ownership in a helper - ruby-on-rails

I have this block in my views:
<% video.members.each do |p| %>
<% if p.id == current_user.id %>
<%= "paid" %>
<% end %>
<% end %>
Basically I'm trying to work out if a member has paid for a video based on whether the id's match.
Maybe this a really bad way of doing it, which case I'd be happy to try and different method.
Assuming it is an ok way of checking this, how could I write a similar statement but as a helper method? I've tried, but it seems you can't write the same logic in helpers as the block just spits out the full array and not the id, meaning it doesn't work.

You should do this instead:
<% if video.members.exists?(id: current_user.id) %>
<%= 'Paid' %>
<% end %>
This will generate a single query to test if the video has been paid by the current_user ;-)
In a helper:
# application_helper.rb
def display_paid_or_not(video)
return '' if video.blank? # similar to .nil?
video.members.exists?(id: current_user.id) ? 'Paid' : ''
end
# in view
<%= display_paid_or_not(video) %>
Hope this helps!

Related

Get model type from each loop

I'm combining two models in my controller, and trying to print them in a similar fashion, but I'd like to do an if statement in an each loop to distinguish one model from the other. My models are comments and likes.
In the controller:
#items = (#user.likes + #user.comments).sort{|a,b| a.created_at <=> b.created_at }
In my view:
<%= #items.each do |item| %>
<% item.name %>
<% end %>
I need an if statement to say IF comment or IF like in the each loop. I've been drawing a blank on the situation.
Assuming you have model Like and Comment
<%= #items.each do |item| %>
<% if item.instance_of?(Like) %>
Something for likes
<% elsif item.instance_of?(Comment) %>
Something for comments
<% end %>
<% end %>
You could do item.class.name as Nithin mentioned, and it'll work fine. However, the more idiomatic way is to use instance_of?. So it'd look like this:
if item.instance_of?(Post)
# do something
elsif item.instance_of?(User)
# do something else
end
Note you're not passing in 'Post' or 'User' as strings - you're passing in the Ruby class constants themselves.
On this topic, it's also worth knowing about Ruby's is_a? and kind_of? methods which work similar to instance_of? but return true if the instance you're testing is an instance of a subclass of the parameter you pass in (more info at Ruby: kind_of? vs. instance_of? vs. is_a?).
What you need to do is to check for the class of the Item of interest.
Basically, each object belongs to a class, and the class name of a comment will be a Comment while that of a like will be a Like.
So, in the loop, check for the class name as:
<%= #items.each do |item| %>
<% if item.class == Comment %>
...comments here
<% elsif item.class == Like %>
...likes here
<% end %>
<% end %>

What syntax do I use if I want to confirm a user is on a certain page?

I have a rails app and in the the application layout view I want the header to show a link ONLY if a user is on a certain page.
How would I write that?
Currently I did
<% if welcome_index2_path? %>
blah...blah...blah
<% else %>
blah...blah...blah
<% end %>
But my if statement is not right, I need the correct syntax.
Just use the current_page? helper!
<% if current_page? welcome_index2_path %>
As Yuri said, you can also use yield.
You can use the yield with content_for:
In your layout:
<%= yield :links %>
In the view for some action, where you need the link:
<% content_for :links do %>
<%= link_to 'Foo', bar_path %>
<% end %>
You also have a content_for? helper method, which returns true, if the content for the given key is given:
content_for?(:foo) => false
content_for(:foo, :bar)
content_for?(:foo) => true
Try this
<% if request.request_uri == welcome_index2_path %>
....
it would be more useful for you to use an actual specific example from your code, as it might be that you want to ignore ids in the url path and just want to test the current controller and action, but i can't tell from your example.
You should do something like this.
<% if current_page?(:controller => 'yours', :action => 'yours') %>

Exit rails gracefully if conditions are met?

I have a code where I would need to exit (php version of die), if certain events occur
Snippet in trace_controller.rb
def show
rule=Rule.new
#order,#order_error=rule.get_order(#order_external_id)
#order_items, #order_items_error=rule.get_order_items(#order)
#order_item_units, #order_item_units_error=rule.get_order_item_units(#order_items)
#outbound_messages, #outbound_messages_error = rule.check_outbound_messages(#order_external_id)
#inbound_messages, #inbound_messages_error = rule.check_inbound_messages(#outbound_message)
......
In show.html.erb
<% unless #order_error.blank? %>
<%= #order_error.html_safe %>
<% else %>
<%= render "trace/display_tabular_data", :data => #order %>
<% end %>
.....
.....
<% unless #order_items_error.blank? %>
<%= #order_items_error.html_safe %>
<% else %>
<% #order_items.each do |order_item| %>
<h5>Order Item</h5>
<%= render "trace/display_tabular_data", :data => order_item %>
<% end %>
<% end %>
......
Most of my functions are dependent on outcome of previous functions. Now take get_order_items function which is dependent on orders. If the order does not exist, there is no need to calculate get_order function as it won't exist either. Additionally, it fires up an error, as it says I am passing it a NIL object when I perform operations on orders inside get_order_item.
Additionally in the show.html.erb - #order_items, and #order_items_error should not even exist if the order does not exist. I just wanna render the function till the order_error, and then stop.
Now, coming from PHP background, I forgot that rails does not have die. So is there an alternate of die? Abort isn't it. I need it to exit disgracefully. Or is my best shot using conditionals if, unless etc...But it will look ugly as the page will become full of them. How would you about it?
To cut off the current action and render the view, you can use return. This will crash with errors if you try to use an unitialized instance variable in the view though.
You can also use render nothing: true which stops the current action and renders nothing.
Perhaps consider redirecting back as well:
flash[:error] = 'There was no order!'
redirect_to :back
I am not sure what exactly you want to do. But this should meet with what you are asking for.
def show
rule=Rule.new
#order,#order_error=rule.get_order(#order_external_id)
unless #order.blank?
#order_items, #order_items_error=rule.get_order_items(#order)
#order_item_units, #order_item_units_error=rule.get_order_item_units(#order_items) unless #order_items.blank?
end
#outbound_messages, #outbound_messages_error = rule.check_outbound_messages(#order_external_id)
#inbound_messages, #inbound_messages_error = rule.check_inbound_messages(#outbound_message) unless #outbound_messages.blank?
end
Similarly, you can add conditions in your view file:
<% unless #order.blank? %>
<% unless #order_error.blank? %>
<%= #order_error.html_safe %>
<% else %>
<%= render "trace/display_tabular_data", :data => #order %>
<% end %>
.....
.....
<% unless #order_items.blank? %>
<% unless #order_items_error.blank? %>
<%= #order_items_error.html_safe %>
<% else %>
<% #order_items.each do |order_item| %>
<h5>Order Item</h5>
<%= render "trace/display_tabular_data", :data => order_item %>
<% end %>
<% end %>
<% end %>
.......
.......
<% end %>
It is just a basic idea what I get from your example, though it was not clear enough to show what you want to achieve. So, whole idea is to check the variable before using it!
One more point I would like to mention, avoid using unless - else, unless should be used alone, if you need to put some logic in else block, why not use if - else. That probably makes more sense than unless - else.

Rails finding a value in a table

Is it possible to call the include? function on a whole table, like this?
<% #user.games.each do |g|
##latestround = g.rounds.order('created_at DESC').first
%>
<% if ##latestround.submittedpictures.isFinalPicture.include?(true) %>
<p>FinalPicture has been played!</p>
<% end %>
<% end %>
The problem i'm getting is that It only works when I put a block on submittedpictures and then loop through each record of this table. However I want to look through the whole table in one go and see if the column 'isFinalPicture' includes a value with 'false'.
Any ideas?
The following snippet works but its not the way i want it (I would get more lines if the round happens to have more 'true' FinalPictures)
<% ##latestround.submittedpictures.each do |s| %>
<% if s.isFinalPicture == true %>
<p>Final Picture has been played!</p>
<% end %>
<% end %>
You could make a scope for it like
class SubmitedPricture << ActiveRecord::Base
scope :final_pictures, where('isFinalPricture = ?', true)
end
then you could see if there is any with only one query
latestround.submittedpictures.final_pictures.any?
Also you should follow the conventions of Rails in naming your Models and everything else. Like submittedpictures should be submitted_pictures

What is the best way using multiple lines of <% %> Tag or <% %> Tag with multiple lines?

Sorry if the title is not enough to understand what i am asking about.
I am rails developer and i used multiple lines of <% %> in my views but now i realized that it's not best practice so i came here and like to you all excellent guys what is the correct way in ROR?
For example if i required to something like following
<% user =User.all %>
<% name= [] %>
<% count = 0 %>
<% for user in users %>
<% name << user.name %>
<% count+=1%>
<% end %>
Can i do it as follows ?
<% user =User.all
name= []
count = 0
for user in users
name << user.name
count+=1
end
%>
I know better way of collecting element from array But above is just example.
But my question is, is it possible and if yes which is the correct way?
I think the correct way is something totally different: move logic out of views.
This blog post explains what I mean.
in start and end must has '<%' or '%>'
Like:
<% users = User.all
name= []
count = 0
for user in users
count+=1
end %>
Using just a single pair of tags per code block is certainly preferable if only because it makes the output smaller.
The code should really rather look like
<% names = User.all.map(&:name) %>
Note that "count" can be obtained via names.size.
If you need to mix <% and <%= you need to switch:
<% for user in User.all %>
<%= user.name %></br>
<% end %>

Resources