Understanding Ruby on Heroku 'config vars' example - ruby-on-rails

In Getting Started with Ruby on Heroku, the following example is given as a use of config vars:
<h1>Getting Started with Ruby</h1>
<p>
Welcome!
</p>
<% for i in 0..(ENV['TIMES'] ? ENV['TIMES'].to_i : 2) do %>
<p>Hello World #<%= i %>!</p>
<% end %>
This method is supposed to run for the number of the TIMES environmental variable, but it doesn't make sense according to my understanding.
I understand the ruby syntax
truthy_or_falsey_value ? evaluates_if_truthy : evaluates_if_falsey
but here we have something that looks similar in syntax but can't be the same thing semantically. Would someone who understands please explain what's going on? Many thanks!

It's called a ternary operator and you're right that these two are equivalent:
ENV['TIMES'] ? ENV['TIMES'].to_i : 2
truthy_or_falsey_value ? evaluates_if_truthy : evaluates_if_falsey
So what's happening is that the ternary operator is used to populate the last argument of a Range:
If `ENV['TIMES'] is nil then the for loop will be:
for i in 0..2
If ENV['TIMES'] is set to 50, the the for loop will be:
for i in 0..50

I have no experience with Heroku but what I understand from that statement is this:
First you have a for loop which will loop from 0 to a specific value. Then you have a conditional statement which, if true, will return ENV['TIMES'].to_i (the .to_i converts the return value of ENV['TIMES'] to an integer), otherwise it will result in 2. Now if you combine both the conditional and the for loop you can figure out what is going on.
If ENV['TIMES'] evaluates to true then the range of the for loop will be from 0 to the value returned from ENV['TIMES'].to_i, otherwise the range will be from 0 to 2. So the final result will be "Hello World" being repeated i times, dependent on whether or not ENV['TIMES'] exists. I am new to Ruby as well and not very familiar with the syntax but hey, that is what I make of it.

Related

Dynamic condition in ruby on rails

I have the following condition:
if "FIX_STRING 0,0,DYNAMIC_STRING" == "FIX_STRING #{integer_from_0_to_5},#{integer_from_0_to_5},#{DYNAMIC_STRING}"
true
else
false
end
How to make it dynamically like this?
if "FIX_STRING 0,0,DYNAMIC_STRING" == "FIX_STRING #{/0|1|2|3|4|5/},#{/0|1|2|3|4|5/},#{/A|B|C|D/}"
true
else
false
end
You're on the right track here, but you've got a very peculiar coding style. The first thing to point out is that a comparison like == already returns a boolean value of true or false, there's no reason for the if which then returns exactly the same thing.
The second thing is that you're comparing a string to another string, so they have to match exactly. Close enough does not count. If you evaluate your other string you get a mess:
"FIX_STRING (?-mix:0|1|2|3|4|5),(?-mix:0|1|2|3|4|5),(?-mix:A|B|C|D)"
Finally, if you're trying to test a string versus a regular expression, you do this:
PATTERN = /\AFIX_STRING [0-5],[0-5],[A-D]\z/
You can test this sort of thing on Rubular to get it right. Here [0-5] means anything in that range. It's short-hand for what you had.
Then you can test arbitrary strings versus this pattern:
"FIX_STRING 3,4,D".match(PATTERN)
# => #<MatchData "FIX_STRING 3,4,D">
So that matched.
Newer versions of Ruby have a match? method that only tests matches, it doesn't return what matched, which you might want to make use of if you're running on 2.3 or later. It's faster than the plain match method, though that only really matters if you're doing a lot of matches inside loops.

Add leading 0 to single digit integers using .sprintf?

Found another question that seemed to be solved by using .sprintf('%02d', 1) to solve this, but I get: 'private method `sprintf' called for 7:Fixnum'.
Does this mean sprintf cant be called on an integer or am I getting it wrong in the calling?
Just looking to pad single digit returns with a leading 0.
Thanks in advance for any help on this!
You might want to try using sprintf like this:
sprintf('%02d', 1)
# => "01"
ie
sprintf('%02d', model.count)
Not calling .sprintf on the number but rather inputing it as a parameter into sprintf()
you may want to try "0#{num}"[-2..-1] or "%02d" % 1

Why in Rails 3, <%= note.html_safe %> and <%= h note.html_safe %> give the same result?

It feels like html_safe adds an abstraction to the String class that requires understanding of what is going on, for example,
<%= '1 <b>2</b>' %> # gives 1 <b>2</b> in the HTML source code
<%= h '1 <b>2</b>' %> # exactly the same as above
<%= '1 <b>2</b>'.html_safe %> # 1 <b>2</b> in HTML source code
<%= h '1 <b>2</b>'.html_safe %> # exactly the same as above
<%= h (h '1 <b>2</b>') %> # 1 <b>2</b> wont' escape twice
For line 4, if we are saying, ok, we trust the string -- it is safe, but why can't we escape it? It seems that to escape it by h, the string has to be unsafe.
So on line 1, if the string is not escaped by h, it will be automatically escaped. On line 5, h cannot escape the string twice -- in other words, after < is changed to <, it can't escape it one more time to &lt;.
So what's happening? At first, I thought html_safe is just tagging a flag to the string, saying it is safe. So then, why does h not escape it? It seems that h and html_escape actually co-operate on using the flag:
1) If a string is html_safe, then h will not escape it
2) If a string is not html_safe, then when the string is added to the output buffer, it will be automatically escaped by h.
3) If h already escaped a string, it is marked html_safe, and therefore, escaping it one more time by h won't take any effect. (as on Line 5, and that behavior is the same even in Rails 2.3.10, but on Rails 2.3.5 h can actually escape it twice... so in Rails 2.3.5, h is a simple escape method, but some where along the line to 2.3.10, h became not as simple. But 2.3.10 won't auto escape a string, but for some reason, the method html_safe already exists for 2.3.10 (for what purpose?))
Is that how it works exactly? I think nowadays, sometimes we don't get what we want in the output and we immediately add html_safe to our variable, which can be quite dangerous, because it can introduce XSS attack that way, so understanding how it exactly works can be quite important. The above is only a guess of how it exactly work. Could it be actually a different mechanism and is there any doc that supports it?
As you can see, calling html_safe on a string turns it into an html safe SafeBuffer
http://github.com/rails/rails/blob/89978f10afbad3f856e2959a811bed1982715408/activesupport/lib/active_support/core_ext/string/output_safety.rb#L87
Any operations on a SafeBuffer that could affect the string safety will be passed through h()
h uses this flag to avoid double escaping
http://github.com/rails/rails/blob/89978f10afbad3f856e2959a811bed1982715408/activesupport/lib/active_support/core_ext/string/output_safety.rb#L18
The behavior did change and I think you are mostly correct about how it works. In general you should not call html_safe unless you're sure that it is already sanitized. Like anything, you have to be careful while using it
in rails 3, all output is using the h helper by default
see http://origami.co.uk/blog/2010/02/rails-3-html-escaping
if you don't want escaping you can use raw

RoR: Why is this if-statement failing?

Why is the second if statement failing in the following code block? The output from the console indicates that the private parameter is 0, so it should be passing? The private parameter is from a checkbox in the new form, that I'm using to set a boolean field in the model.
if (((params[:note])[:text]) != "")
logger.debug("passed first test")
logger.debug(((params[:note])[:private]))
if (((params[:note])[:private]) == 0)
logger.debug("passed second test")
end
end
console output
passed first test
0
Completed in 61ms (DB: 1) | 302 Found [http://localhost/notes]
Thanks for reading.
Form fields are submitted as strings so params[:notes][:private] will actually contain "0" not 0.
You could use either params[:notes][:private] == "0" or params[:notes][:private].to_i == 0 to get the comparison you're after.
If you want to treat non-integer values (including empty strings and missing values) differently from 0, you should not use String#to_i. I would recommend checking the String value in these cases.
You can use Object#inspect (as mentioned by #sepp2k) and Object#class when debugging to get a better idea of what types things are. When using script/console, I find ap (or pp) to be rather handy.
A side note: In Ruby you don't need so many parentheses. Here's the your example after a little bit of cleanup:
unless params[:note][:text].blank?
logger.debug "passed first test"
logger.debug params[:note][:private].inspect
if params[:note][:private].to_i == 0
logger.debug "passed second test"
end
end
In cases where two expressions print the same, but aren't equal, you usually have different types. For example "0", :"0" and 0 both print as 0, but aren't actually equal to each other.
logger.debug(params[:note][:private].inspect) should give you more meaningful output, indicating the type of the object as well as the contents (i.e. if it's a string it's surrounded by quotes, if it's a symbol it starts with a colon, etc.).
The values in params are generally strings, so the value of params[:note][:private] is very probably "0", not 0.

Does Ruby/Rails have a ++ equivalent?

I guess I just got used to saying things like:
x++
in PHP and Java land. But when I tried this in my Rails code it had a fit:
compile error
/users/gshankar/projects/naplan/app/views/answers/new.html.haml:19: syntax error, unexpected ';'
/users/gshankar/projects/naplan/app/views/answers/new.html.haml:23: syntax error, unexpected kENSURE, expecting kEND
...}\n", 0, false);_erbout;ensure;#haml_buffer = #haml_buffer.u...
^
/users/gshankar/projects/naplan/app/views/answers/new.html.haml:26: syntax error, unexpected $end, expecting kEND
I googled around a bit for Ruby/Rails operators for a reference to ++ but couldn't find anything. For a language which focuses on writing less I find it a bit strange that there wouldn't be a ++ equivalent. Am I missing something?
Try this:
x += 1
x+=1 is the best you can do in Ruby.
For a detailed explanation, see Why doesn't Ruby support i++ or i--​ (increment/decrement operators)?
While as other answers point out x += 1 and x -= 1 is one way to do this. The closest Ruby gets to the --/++ operators are the prev()/next() (next has an alias of succ()) methods which return the previous/next items in sequence and are available on unambiguous strictly ordered classes (like String).
x = 4 # => 4
x.succ # => 5
x.prev # => 3
y = 'ABC' # => 'ABC'
y.succ # => 'ABD'
y.prev # => 'ABB'
Unfortunately, none of these implicitly do assignment which is what the original question was asking about. igul222's answer links to a post from Ruby's creator explaining why this is not possible.
Ruby has very powerful collection processing capabilities that eliminate most needs for these kinds of assignments. In all but the most complex alogrithms, which involve processing multiple collections at different rates in parallel. You should be asking yourself why you need increment/decrement. Because the Ruby way to do operations where increment and decrement operators are commonly used is with an iterator.
Such as each_with_index which executes a given block for each element/index pair in the array.
For example, this code will iterate through an array outputting the string representation fo each element and the parity of its index.
array = ["first", "second", "third","fourth","last"]
array.each_with_index do |object,index|
puts index % 2 ? "even" : "odd"
puts object.to_s
end
Edit: Removed Fixnum extension providing postfix increment because it doesn't work. Upon closer inspection there's nothing stopping you from adding it, but it would involve writing your feature in C, and a recompile.
Edit 2022: Added comment about prev/next/succ functions which are closer in behaviour to the decrement/increment function of --/++ operators
You have to use x+=1 instead.
http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Operators

Resources