Rails 3 - Object.try syntax - ruby-on-rails-3

How would I avoid nil checks using Object.try for the following?
<%= image_tag(PeriodState.where("sla_id = ?", sla.id).last.state.image_file) %>
I've tried .try many different ways, but still receive errors, so my syntax is off. Thanks in advance!

try isn't really appropriate for this: whatever the outcome image_tag will always be called - so you might end up calling it with nil. You need to check whether the image exists first then create an image tag only in this case. So I would get the PeriodState in your controller and have a simple if in your view:
# in controller
#period_state = PeriodState.where("sla_id = ?", sla.id).last
# in view
<%= image_tag(#period_state.state.image_file) if #period_state %>
Of course this won't work if either state or image_file could also be nil.

Related

How to ask if something is .present? in a view in Roda

I am converting a Rails app to Roda. Here's a section of a partial.
# _banner.erb
<% if banner.present? %>
...
<% end %>
This returns the error: NoMethodError: undefined method 'present?' for []:Array.
How can I get Roda to support something simple like checking if a variable is present?
All present? does is negate blank? which in turns looks like this. You could add this to your helper/service classes depending on your setup.
def present?
!blank?
end
def blank?
respond_to?(:empty?) ? !!empty? : !self
end

Rails STI Mystery - Why does type change from Class to String in view?

This is long so I hope you'll bear with me...
I have a model called Update with two subclasses, MrUpdate and TriggeredUpdate. Using single-table inheritance, added type field as a string to Update.
In my view I'm checking which type it is to decide what to display. I assumed since type is a string, I should do
<% if #update.type == 'MrUpdate' %>
This failed, i.e., it evaluated to false when the update was an MrUpdate. I noticed that at this point, #update.type.type is Class. OK, whatever, thought I, so I changed it to:
<% if #update.type == MrUpdate %>
and it worked, i.e., the comparison evaluated to true when the update was an MrUdpate. Then I did it again lower down in my view and it failed again (i.e., it evaluated to false when the update was an MrUpdate.)
Turns out the culprit is a couple of <%= link_to ... %> calls I use and make into buttons with jQuery. If I put this code in my view:
<br>
<%= #update.type.type %><br>
<%= #update.type %><br>
<%= link_to 'New Note', new_note_path(:update_id => #update.id), :class => "ui-button" %>
<br>
<%= #update.type.type %><br>
<%= #update.type %><br>
What I see is:
Class
MrUpdate
(the New Note button)
String
MrUpdate
It's changing from a class to a string! So what the heck am I doing wrong or missing here? Why should a link_to do that? First I'm not clear why it's not a string in the first place, but then really confused as to why it would change...?!? Any help or explanation would be helpful. I can just code it one way at the top and another way at the bottom, but that way madness lies. I need to understand why this is happening.
I figured out what the issue is here. Thanks to fl00r for pointing the way.
Yes, type is a reserved in Ruby 1.8.7 which tells you the class of the object you call it from. But it's also true that it is the name of the field used in Rails to indicate single-table inheriance and to store the name of the class of each instance of the subclass.
So I naively tried to access the value of the type field using #update.type. But what this was doing at the top of the view was calling the type method of the Object class in Ruby. For whatever reason, after the link_to calls, it was then access the value of the type field of the updates table.
While trying to figure this out I called #update.type in the Rails console and saw this message: "warning: Object#type is deprecated; use Object#class". Finally it registered what I was doing. When I changed my calls to:
<% if #update.class == MrUpdate %>
everything works as expected. I never saw a call to determine the type in any of the pages I found via Google about STI. This despite the fact that they all recommended using only one controller, wherein sometimes you must need to determine the class of the instance you have.
So, dumb mistake--pilot error. But maybe this will help someone else who gets tripped up on this.

How to use to_sentence with an AR collection

I have User.all, which returns 3 results.
How can I make it so I can render each result to something like:
Foo, Bar, and Foobar
Which when rendered in the browser, will display as:
Foo, Bar, and Foobar
I know about the to_sentence helper. But not very sure how to execute this, since User.all returns 3 hash objects. I can use .map(&:first_name), but how will I be able to provide the route path in the link_to method.
Looking for an approach that works.
I think you're looking for something like this. (answer updated)
In a helper:
module ApplicationHelper
...
include ActionController::UrlWriter
def generate_user_links_sentence
links = User.all.collect do |user|
link_to user.first_name, user_path(user)
end
links.to_sentence
end
...
end
# Example: <%= generate_user_links_sentence %>
You can separate out the generation logic into your controller if you so wish, but it's difficult enough accessing route paths from a helper, let alone the controller. There may be a better way to do this in a view, but this is all I can really think of right now.
Update: Just in a view:
<%= User.all.collect{|u| link_to u.first_name, user_path(u)}.to_sentence %>

RoR, Passing a variable into view gives a null object

I am setting a variable in my controller but for some reason it is not getting set. I tried it two ways.
def update
# #available_cars = Car_info.where("user_id = ?", session[:user_id])
#available_cars = Car_info.find_by_user_id(session[:user_id])
end
In my view I do this.
<% #available_cars.each do |car| %>
<%= car.name %>
<% end %>
What I intend to do is populate the #available_cars into a drop down list but I can't even get them to print. I know the session[:user_id] is set because I print it and access it elsewhere.
I get this error...
Expected D:/RailsProjects/mileage/app/models/car_info.rb to define Car_info
in my controller
app/controllers/active_car_controller.rb:6:in `update'
Any help would be appreciated. New to RoR.
I see your controller method is named 'udpate' instead of 'update' - could that be your problem?
You need to change your query to:
#available_cars = Car_info.find_all_by_user_id(session[:user_id])
The find_all part will get you all records, whereas find only gets you the first. Another way to write this is:
#available_cars = Car_info.where("user_id = ?", session[:user_id])
Ideally, you want your class to be called CarInfo, not Car_info.

How can I use the 'unless' keyword in a view?

Can anyone tell me if there's a Rail3 replacement for something like this:
<%= unless #page.new_record? || !#page.background_image? %>
bla
<% end %>
I'm trying to display a checkbox on a form only when a user edits. Not when they create.
I think the statement is ok, but should not be included in your view. Instead, create a model method, probably named is_editable? or something, that includes this statement. Then get an instance variable in your controller and use that instead.
Logic in views is a very bad idea :)
Your mistake is including the = in the ruby code.
<% unless #page.new_record? || !#page.background_image? %>
bla
<% end %>
However, as other users have stated, it is probably better to hide this logic in the model rather than in the view. Additionally it considered a best practice to only use unless if there is only one boolean statement. It starts to get harder and harder to read when you have ors and nots included there.
<% if #page.is_editable %>
blah
<% end %>
This would be a nicer version, and even better than that (depending on how complicated 'blah' is) would be to hide the whole thing in a helper method.
<%= some_special_checkbox(f) %>
The parameter f would be the form object so that your helper can render the checkbox for the form.
You can write it like this:
<%= "bla" unless #page.new_record? || !#page.background_image? %>
May be you should write separate method with more human-readable name and replace this condition with one method. Try to keep your view as much cleaner as possible