I'm writing a helper method that adds a class to an element depending on whether two numbers are equal to eachother. My code is as follows:
<% for note in #company.convertible_notes.each %>
<% if note.id %>
<li class="tab <%= note_nav(params, note.id) %>"><%= link_to "#{note.security_series} #{note.security_class} Note", convertible_note_convertible_notees_path(note) %></li>
<% end %>
<% end %>
note_nav calls the following helper:
def note_nav(params, note)
"active" if params[:controller]=="convertible_notees" && note.to_s==params[:converible_note_id].to_s
end
Now the surprising thing is that I cannot get the expression note.to_s==params[:converible_note_id].to_s to register true. Even when I know the two numbers being compared are both "1". I checked it using my log:
logger.debug "are they equal? #{note.to_s==params[:converible_note_id].to_s} note.id is #{note} note params are #{params[:convertible_note_id]}"
Which yields the following log entry:
are they equal? false note.id is 1 note params are 1
I would guess that they're two different types but given that I've converted both of them to_s, I don't know how that would be an issue. I've used this exact same technique on a few combinations of other models and have been completely error free. Any idea as to what might be going on?
Thanks in advance
Look at your test
"are they equal? #{note.to_s==params[:converible_note_id].to_s} note.id is #{note} note params are #{params[:convertible_note_id].to_s}"
:converible_note_id and :convertible_note_id are other keys, a type error
You could also get that output if one of the variables contains non-printing characters:
note = "1\000"
params = {
convertible_note_id: 1
}
puts "are they equal? #{note.to_s==params[:convertible_note_id].to_s}"
puts "note.id is #{note} note params are #{params[:convertible_note_id]}"
--output:--
are they equal? false
note.id is 1 note params are 1
To see what's really in a string, you should always use inspect():
p note.to_s, params[:convertible_note_id].to_s
--output:--
"1\u0000"
"1"
Related
Having some trouble with nested hash parameters. Product has many features. Say product 1 has features foo and baz.
I'd like to pass both the product and all of the features to query string parameters in a link_to so that it ends up looking like this:
"/puppies/new?features%5Bbaz%5D=qux&features%5Bfoo%5D=bar&product=1"
I am currently trying this, which gets a syntax error for reasons that are probably obvious to people that are not me.
<% Product.each do | product | %>
<%= link_to(new_puppy_path(product: product, features: { product.features.each
{ | feature| feature.name : 'feature.'} } ), class: 'slorp') do %>
// stuff inside the link
<% end %>
<% end %>
Any idea what I'm doing stupid here?
UPDATE: I have updated the code to:
<%= link_to(new_puppy_path(product: product, features: product.features.each{|feature| {feature.name.to_sym => feature.feature_colors.first}}), class: 'image') do %>
This is much closer, as my output URL is now:
/puppies/new?features%5B%5D=3&features%5B%5D=2&product=2
I am just missing the name of the feature in-between the %5B and %5D - not sure why the feature name is not showing up.
You need to use map instead of each. Each returns the original array itself on which it is operating. While map returns the elements from the block.
Fixed. Pulled creating the hash up into the model:
def reco_features
list = Hash.new
feature_colors.each do |feature_color|
list[feature_color.feature.name] = feature_color.id
end
return list
end
Then updated the link_to:
<%= link_to(new_puppies_path(product: product, features: features.reco_features ), class: 'slorp') do %>
Not sure why the inline wasn't working, but this fixed it. Required some additional context outside of the initial question, which I did not realize at the time. Apologies and thanks to all.
I have a little problem...
My View:
--html---
<% #things each do |thing| %>
<% other = #others.find_by(:ID == thing.ID)%>---->it runs just once. Why?
<div>
<p>thing.ID</p> ---------------> This is correct.
<p>other.NAME</p> -------------> But it isn't. It is always same (fisrt value..).
</div>
<%end%>
--html--
I like this, that the other.NAME changes too. Thanks for the help!
You have == when you need =>
:ID == thing.ID is evaluated to false, which leads to:
#others.find_by(false) which happens to return the first record every time.
Also, your naming of attributes is not standard - by rails convention they should be small letters: other.name
you can used following query to find 'other'
other = #others.find_by_ID(thing.ID)
if record not found it will return 'nil' and not 'record not found' error.
You can used
other.try(:NAME)
other.name will give error if 'other = nil'.
Can someone explain the logic behind this code?(This is the correct code btw)
<% if #request.query['first_name'] && !#request.query['first_name'].empty? %>
Welcome! <%= #request.query['first_name'] %>
<% else %>
Hi! What is your name?
<% end %>
My intuition is to write the following instead:
<% if #request.query.inspect['first_name'].empty? %>
Hi! What is your name?
<% else %>
Welcome! <%= #request.query.inspect['first_name'] %>
<% end %>
I am trying to have a user form where people can input their names, when there is no input yet the text above the form says "Hi! What is your name?" when there is an input it has a message saying "Welcome! *User_name*"
The first block of code is not intuitive to me, the second one would make more sense.. ANy advice on how to understand the code?
Your intuition is correct, though you need an alternative to empty?. Rails adds a few different methods you can use:
blank? returns true if the receiver is nil, an empty array, string, or hash, or a string with only whitespace.
present? returns true if blank? is false. So your condition could be:
<% if #request.query['first_name'].present? %>
Welcome...
(I find it's always more intuitive to start with the positive condition - it would work just as well to check blank?).
Edit: It's pretty likely you can skip the query method entirely if all you expect there is either a string or nil. Just use:
<% if #request.query['first_name'] %>
You need to check if it's nil before you can check if its empty, because you are checking a Hash#empty?
irb(main):001:0> nil.empty?
NoMethodError: undefined method `empty?' for nil:NilClass
from (irb):1
irb(main):002:0> {}.empty?
=> true
The code checks for hash key existence, then check if the value of the hash is present. This action can be done in one check using:
#request.query.try(:[], 'first_name').empty?
You can avoid the first condition inside the if statement by transforimng nil into an empty string. I don't know if that is what you meant to do but you almost had.
First, you shouldn't call inspect in the hash because it will transform the entire thing into a 'complex' string. What you want to do turn only the value inside the first_name option, because in that case if the name exists it will still be the same, and if it doesn't, it will be turned into "nil".
Secondly, the method inspect isn't the best choice here, because the returned string will never be empty, given that nil.inspect => "nil". What you should use is the method to_s, wich will behave like this when applied to nil: nil.to_s => "".
Finally, you could update your code to:
<% if #request.query['first_name'].to_s.empty? %>
Hi! What is your name?
<% else %>
Welcome! <%= #request.query['first_name'] %>
<% end %>
Is there a way to write a clean if nil then in a view. Assuming my lack of ruby is biting me here. Example,
If object nil, then return, nothing found
have
<%= #objects.count if #objects %>
want something like this
<%= #objects.count if #objects then "nothing found" %>
There are many ways to write something like this.
Something simple would be:
<% if #objects %>
<%= #objects.count %>
<% else %>
nothing found
<% end %>
If you get into a slightly more complex conditional I would suggest moving the logic into a helper and call it from the view. ex:
<%= count_for(#object) %>
Here's a good solution for you:
<%= "nothing found" unless #objects.try(:length).to_i > 0 %>
One of the issues is that you can't run count on a nil object. Therefore you need to use Rails' super handy .try() method to return nil when #objects = nil, rather than NoMethodError.
Next issue: You can't make a comparison between nil and a number using > so you need to convert the results of #objects.length to an integer which will return 0 for nil.
Lastly, try calling length rather than count. This will avoid running any extra queries when #objects is defined.
Avoids: SELECT COUNT(*) FROM 'objects'
Also if you want to display the count using this one-liner technique you can simply write up a shorthand if/else statement as follows:
<%= #objects.try(:length).to_i > 0 ? #objects.length : "nothing found" %>
One last option:
Use the pluralize method, which can handle a nil count:
Showing <%= pluralize( #objects.try(:length), 'object' ) %>
Sorry, I know this is pretty late, but hopefully helpful for someone else!
I'm trying to get some code to display based on a condition. I have a boolean field in a table called "show_weekly". What I'm attempting is: If the column == 1 then display the first line else display the 2nd line of code. for some reason it's only showing the 2nd line.
<% if #listing.show_weekly == 1 %>
<%= number_to_currency(#listing.price/4, :unit => "£") %> / week
<% else %>
<%= number_to_currency(#listing.price, :unit => "£") %> / month
<% end %>
any help is greatly appreciated. thanks
The value of a boolean column will either be false or true in ruby, not 0 or 1. So you should do:
<% if #listing.show_weekly %>
instead of <% if #listing.show_weekly == 1 %>
I'd suggest adding a method to your model
def print_price
#p = this.show_weekly? ? this.price / 4 : this.price
number_to_currency (#p, :unit => "£")
end
you need to check if it equals true, not 1
A boolean value is stored as a 1 or a 0, but it is always interpreted as true or false before being returned from the model. This is a source of a lot of confusion.
Using the accessor method show_weekly? can help because a question-mark in a method name usually indicates it will return a boolean value, or something that can be evaluated as boolean.
It will be a lot more readable if you have:
<% if #listing.show_weekly? %>
...
<% else %>
...
<% endif %>
Wherever possible, avoid comparing to specific hard-coded values. For instance, the following is redundant and yet I see it all the time:
# Example: Comparison to nil
if (#something == nil)
# Should be: Checking if initialized
if (#something)
# Example: Comparison to true
if (#something == true)
# Should be: Testing directly
if (#something)
As there are only two values that evaluate as false in Ruby, nil and false, it is generally the case that anything that is not true is nil. Occasionally you will have boolean columns that can be true, false or nil if it is not defined, but this is unusual and can trip up people.
If #listing.show_weekly contains a boolean value, just test for true :
<% if #listing.show_weekly %>
.....
<% else %>
....
<% end %>
Notice you don't even need the "== true". This is because the IF statement only looks to see if there's a true value returned from whatever expression follows it. If #listing.show_weekly contains a value of true then that's all the IF statement sees if that's all you provide it.