ruby: do nothing (dummy) function - ruby-on-rails

When working with ruby on rails code, what is the conventional way (or most elegant way) to let rails do nothing?
For example when debugging and commenting out a line where there has to be a statement:
begin
#some_commented_out_function
rescue => e
[...]
end
Is there a dummy function I quickly can put in instead of the commented out line? What is the convention for this?

Ruby doesn't have a pass or no-op statement. In your example, that code would work as written, with or without a comment.
If you'd like to make it explicit, a line with just nil or a comment explaining the method would probably be considered conventional.

Related

Which syntax will recomend between try and &. when we're dealing with nil value in Ruby on Rails?

Like the title, from 2.3.0 ruby version. We can use Safe Navigation Operator(&.) instead of try for dealing with nil value in Rails.
But when I use the new syntax, my reviewer told that is not good for reviewer, or someone else about the meaning my code.
So I would like to know which syntax I should use when work with nil value?
nil.try(:method)
nil&.method
&. works like #try!, not #try. documentation
#try not native in ruby but it is provided by rails.
Safe navigation #&. is almost 3~4 times faster than using the #try
require 'active_support/all'
require 'benchmark'
foo = nil
puts Benchmark.measure { 10_000_000.times { foo.try(:boo) } }
puts Benchmark.measure { 10_000_000.times { foo&.boo } }
Output
1.210000 0.000000 1.210000 ( 1.211835)
0.360000 0.000000 0.360000 ( 0.363127)
As mentioned in #dinjas's answer, .try is a method provided by Rails, whereas &. is a method that is provided by Ruby itself, and hence, will be usable outside Rails apps as well.
Additionally, the two operators do NOT work in EXACTLY the same manner. The safe navigation operator prevents NoMethodErrors only for those cases when it is invoked on a value which is nil. For example:
a = nil
a&.do_something # Result: nil
a = false
a&.do_something # Result: NoMethodError: undefined method `asd' for false:FalseClass
a.try(:do_something) # Result: nil
As seen above, while .try handles falsy values as well and returns nil as the response when a method is invoked on an object that does not support it. However, &. does not handle that and invokes methods on false as well. The same applies to blank strings.
In terms of what you should use, I believe that decision should be taken by having a discussion with your team. I believe neither of the methods are incorrect and either can be used. However, I would strongly recommend not using BOTH try and &. throughout the codebase as that could lead to unintended effects if the codebase grows large.
This blog by Georgi Mitrev describes the safe navigation operator in more depth and I would recommend giving it a read once.
try is a method provided by Rails' Active Support
The safe-navigation operator is provided by Ruby itself (since version 2.3).
If you were to open a Ruby console (not Rails), and define a method foo:
def foo
:bar
end
You could see something like the following:
>> nil.try(:foo)
Traceback (most recent call last):
4: from /Users/dinjas/.rbenv/versions/2.6.1/bin/irb:23:in `<main>'
3: from /Users/dinjas/.rbenv/versions/2.6.1/bin/irb:23:in `load'
2: from /Users/dinjas/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
1: from (irb):7
NoMethodError (undefined method `try' for nil:NilClass)
>> nil&.foo
=> nil
IMHO, I prefer using Ruby methods over Rails methods as they are usable outside of the context of Rails.
That said, I also feel that whichever you use, it should be used sparingly. In my experience, it's a symptom of writing timid code (see Avdi Grimm's book, Confident Ruby).

What is the difference between `try` and `&.` (safe navigation operator) in Ruby

Here is my code:
class Order < Grape::Entity
expose :id { |order, options| order.id.obfuscate }
expose :time_left_to_review do |order, options|
byebug
order&.time_left_to_review # ERROR
end
expose :created_at { |order, options| order.last_transition.created_at }
end
# NoMethodError Exception: undefined method `time_left_to_review' for #<Order:0x007f83b9efc970>
I thought &. is a shortcut for .try but I guess I was wrong. May someone point me to the right direction regarding what I am missing?
I feel like it's not ruby related. Grape maybe? Though I don't get how it could be.
&. works like #try!, not #try.
And here is description of #try! (from documentation):
Same as #try, but will raise a NoMethodError exception if the receiving is not nil and does not implemented the tried method.
So basically it saves you from calling a method on nil, but if an object is presented it will try to call its method as usual.
The quote is from Rails Documentation, and so it's important to emphasize
that Ruby does not provide #try; it's provided by Rails, or more accurately ActiveSupport. The safe navigation operator (&.) however, is a language feature presented in Ruby 2.3.0.
The try method ignores a lot of things, it just gives it a shot and calls it a day if things don't work out.
The & conditional navigation option will only block calls on nil objects. Anything else is considered to be valid and will proceed with full consequences, exceptions included.
I am arriving to the party a bit late here, the other answers have covered how it works, but I wanted to add something that the other answers have not covered.
Your question asks What is the difference between try and &. in Ruby. Ruby being the key word here.
The biggest difference is that try doesn't exist in Ruby, it is a method provided by Rails. you can see this or yourself if you do something like this in the rails console:
[1, 2, 3].try(:join, '-')
#=> "1-2-3"
However if you do the same thing in the irb console, you will get:
[1, 2, 3].try(:join, '-')
NoMethodError: undefined method `try' for [1, 2, 3]:Array
The &. is part of the Ruby standard library, and is therefore available in any Ruby project, not just Rails.
In addition to the above answers, I am adding some examples.1
account = Account.new(owner: Object.new)
account.try(:owner).try(:address)
# => nil
account&.owner&.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`
account.try!(:owner).try!(:address)
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`
As we can see, try doesn't check if the receiver responds to the given method or not. Whereas try! and &. behaves the same. If the receiver responds to the address method, all of them will return the same result. I prefer using &. as it looks more cleaner.
For more information on The Safe Navigation Operator (&.), I have found this blog really helpful https://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/

Strange behaviour in a single line ruby sentence having a block and an if clause

I don't know why these two pieces of code behave different in Ruby 1.8.7 since one seems to be the single line version of the other.
The first piece of code (it works as it should):
if #type.present?
type = #type
orders = Order.where{type.eq(type)}
end
The single line version (it doesn't work at all, no error but seems no execution too):
orders = Order.where{type.eq(type)} if (type = #type).present?
NOTE: I'm using the squeel gem, that is the reason a block follows the where method. Also the variable type has to capture the instance variable #type since the execution context changes inside the block and the instance variables are not shared between the main context and the block context.
NOTE 2: I have to use Ruby 1.8.7 for legacy reasons.
Any idea? Thank you!
There is a problem with the order of parsing of your code. Variables need to be defined before they are used.
Even though variables defined inside if statement clauses "leak" out into the current scope, they do not leak "backwards" in Ruby code.
Ruby is a little bit curious in that way that variables need to be defined before the parser parses the code. The parsing is done from top to bottom and left to right.
Hence since the variable type is defined after your block code where you use it, it will not be available in the block.
Example:
>> 3.times { puts x } if (x = 123)
NameError: undefined local variable or method `x' for main:Object
The reason you don't get any error message is that in Ruby 1.8 type is a method that is a synonym for Object#class.
So what your code is really doing is (probably):
orders = Order.where{type.eq(this.class)} if (type = #type).present?
To fix it you have to define type before you use it. Therefore you can't really turn that into a one-liner unless you simply do this instead:
orders = Order.where{type.eq(#type)} if #type.present?
All in all it's not a good idea in Ruby 1.8 to use type as a variable in Rails models, because of the Object#class issue it will most likely bring you headaches in the long run.
similar problem that i got was that 'type' is a keyword in database, it allows for our model to have the field as 'type' but it works strangely in different conditions. if changing the name is an option for you then check after changing it, worked for me...
gem Squeel uses instance_eval method when calls block which passed to where. So, there is no any #type in squeel instance. If you want to use methods or variables from another context, try to wrap it into method my with block
orders = Order.where { type.eq my { #type } } if #type.present?
PS sorry for my English

Why URI.escape fails when called on ActionView::OutputBuffer?

I'm upgrading an application from Rails 2 to Rails 3. Apparently, calling render() now returns ActionView::OutputBuffer and not String. I need to pass the results of render() to URI.escape(), and this fails with exception...
Here is my brief testing in the console
ob = ActionView::OutputBuffer.new("test test")
URI.escape(ob)
`NoMethodError: undefined method 'each_byte' for nil:NilClass`.
from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:307:in `block in escape'
from ..../ruby/1.9.1/gems/activesupport-3.2.1/lib/active_support/core_ext/string/output_safety.rb:160:in `gsub'
from ..../ruby/1.9.1/gems/activesupport-3.2.1/lib/active_support/core_ext/string/output_safety.rb:160:in `gsub'
from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:304:in `escape'
from /opt/ruby19/lib/ruby/1.9.1/uri/common.rb:623:in `escape'
Moreover, calling to_s on OutputBuffer returns same OutputBuffer class, so I cannot even convert this buffer into a honest string?
ob.to_s.class
ActionView::OutputBuffer
Of course, calling URI.escape("test test") returns "test%20test" as expected, so this is not URI problem.
Environment:
ruby 1.9.3p125 (2012-02-16 revision 34643) [i686-linux]
Rails 3.2.1
My question is: Why does this happen and how can I work around this issue?
Update: Apparently, using '' + ob as a form of ob.to_s converts OutputBuffer to String, which effectively works around the problem... But my question 'why does this happen' still remains, e.g. is this a bug, should I report it, or I'm doing something wrong?
This is a bug in Rails:
When calling gsub with a block on an ActiveSupport::SafeBuffer the global variables $1, $2, etc. for referencing submatches are not always properly set (anymore?) when the block is called.
This is why URI.escape (and any other function that uses gsub() will fail on ActiveSupprt::Safebuffer.
There are several discussions about this, apparently the safest route right now is to call to_str before passing SafeBuffer to anything that can call gsub, e.g. URI.encode, escape_javascript and similar functions.
My other quesion about to_s returning the same class - obviously safe buffer will return itself and not a bare String, this is by design. In order to get a true String, .to_str can be used.
This is due to the fact that Rails 3 introduced the concept of safe buffers
In Rails3 your Views are protected by XSS by default by making all rendering be safely escaped unless you explicitly use the raw() helper or html_safe
This is a dumb bug that i'm currently encountering in Rails 5. My stupid workaround was to do something like
ob = ActionView::OutputBuffer.new("test test")
URI.escape(ob.to_sym.to_s)
Again it works, but i'm still looking for a cleaner solution.

How to get generators call other generators in rails 3

I am experimenting with gem development, right now specifically generators. So far I have successfully created two generators that do their job just perfectly. These two generators are in the same directory.
However, right now I have to call each of them separately.
What I'd like to do is just call one generator and have that generator call all the other ones. Just would type
rails g generator_name
and this would call x other generators.
Does anyone know how would I got about doing this?
Help is much appreciated, thanks!
In your generator, you can just call
generate "some:generator" # can be anything listed by 'rails g'
for example:
module MyGem
class InstallGenerator < Rails::Generators::Base
def run_other_generators
generate "jquery:install" # or whatever you want here
end
end
end
By the way, if you are working on Rails 3 gems, this question can also help out:
Rails 3 generators in gem
Another possibility is to use something like
invoke 'active_record:model', 'foo bar:string baz:float'
which is not as clean as generate, but has one advantage: When your generator gets called via rails destroy, this call -- like may other of Thors actions -- will try to revoke the action of the generator you invoke.
There's a catch however: Probably due to Thors dependency management, this only works once per generator you want to call, meaning that a second invoke of the same generator will do nothing. This can be circumvented by using a statement like
Rails::Generators.invoke 'active_record:model', '...', behavior: behavior
instead. In this case you have to explicitly pass through the behavior of your generator (which is a method returning values like :invoke, :revoke and possibly others, depending on which command -- rails generate, rails destroy, rails update, etc. -- called your generator) to achieve the same result as above. If you don't do this, the generator you call with Rails::Generators.invoke will also be executed when running your generator with rails destroy.
Alternatively you could stick to invoke and try to tamper with Thors invocation system. See also here for example.
Generators are based off of Thor, so you can use the apply method.
This is what the Rails Templater gem does. (Here's a walk through the Rails Templater gem.)
Take a look at the scaffold generator that comes with rails.
/Users/XYZ/sources/rails/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
def manifest
record do |m|
#....rest of the source is removed for brevity....
m.dependency 'model', [name] + #args, :collision => :skip
end
end
Here the scaffold generator is using the model generator. So take a look at the dependency method. You can find the API docs for it over here.

Resources