Rails Optional Argument

Rails optional argument

It's as simple as this:

class Person
attr_accessor :name, :age

def initialize(name = '', age = 0)
self.name = name
self.age = age
end
end


Person.new('Ivan', 20)
Person.new('Ivan')

However, if you want to pass only age, the call would look pretty ugly, because you have to supply blank string for name anyway:

Person.new('', 20)

To avoid this, there's an idiomatic way in Ruby world: options parameter.

class Person
attr_accessor :name, :age

def initialize(options = {})
self.name = options[:name] || ''
self.age = options[:age] || 0
end
end

Person.new(name: 'Ivan', age: 20)
Person.new(age: 20)
Person.new(name: 'Ivan')

You can put some required parameters first, and shove all the optional ones into options.

Edit

It seems that Ruby 2.0 will support real named arguments.

def example(foo: 0, bar: 1, grill: "pork chops")
puts "foo is #{foo}, bar is #{bar}, and grill is #{grill}"
end

# Note that -foo is omitted and -grill precedes -bar
example(grill: "lamb kebab", bar: 3.14)

A method with an optional parameter

def some_func(variable = nil)
...
end

Best way to send() optional parameter in Rails

If you're using Ruby 2.2.0 or later you can call #itself on any object and get that object. So in your example you can do

def foo param_1, param_2 = :itself
object.send(param_1).send(param_2)
end

And it will be the same as

def foo param_1, param_2 = nil
thing = object.send(param_1)
if param_2
thing.send(param_2)
else
thing
end
end

I also second Surya's advice to always use #public_send instead.

Fetch optional parameters not working in rails

The link: true argument is getting swallowed up by the joining variable.

Let me explain. Here's the method signature:

def send_email(id, joining = false, options={})

Now, if you call that method with: send_email(123, link: true), then we end up with:

id = 123
joining = {link: true}
options = {}

To prevent this unwanted affect, you need to explicitly pass all three variables: send_email(123, false, link: true).

...But wait, there's an even better way! Use keyword arguments instead. You can define the method like this:

def send_email(id, joining: false, **options)

And call it exactly like you were doing before:

send_email(123, link: true)

The only minor difference (which is frankly a clear improvement) is that you'll need to invoke the method slightly differently if you want to set joining = true:

# Before:
send_email(123, true, link: true)

# After:
send_email(123, joining: true, link: true)

Ruby Object Initialize with Optional Arguments

If you're going to do that you need to accept not an array of arguments (varargs style) like you've specified, but either an options hash or the new keyword-args style option.

The classic approach:

def initialize(attributes = nil)
attributes and attributes.each do |k,v|
instance_variable_set("@#{k}", v) unless v.nil?
end
end

The new keyword-arguments approach:

def initialize(**options)
options.each do |k,v|
instance_variable_set("@#{k}", v) unless v.nil?
end
end

You can also subclass OpenStruct to get behaviour like this for free.

Keep in mind there's a new option style that might be a good mix of both these approaches:

def initialize(sid: '123', token: '...', ...)
@sid = sid
@token = token
# ...
end

You can specify defaults for the named keyword arguments.

Is it possible to have a scope with optional arguments?

Yes. Just use a * like you would in a method.

scope :print_args, lambda {|*args|
puts args
}

ArgumentError with optional parameters

In Ruby < 3.0, if the last argument is a hash, and the method being called accepts keyword arguments, then it is always converted to keyword arguments.

Ruby 3.0 fixes this.

You should upgrade to Ruby 3.0 if you can, or else think of a different API.

Order of optional parameters in initializer

If you define optional parameters before AND after mandatory parameters, in some cases it will be impossible to decide how a goven list or arguments should map to the defined parameters.

In your case, when defining this method:

class A
def initialize(a = "default val", b, c = [])
#...
end
end

How would you handle this when giving two arguments,. i.e.

A.new 'hello', 'world'

You could then assign

a = 'hello'
b = 'world'
c = []

but you could equally set

a = 'default val'
b = 'hello'
c = 'world'

Given this unambiguity, Ruby rejects those constructs. You thus have to define all optional parameters either at the front or the back of your parameter list, while it is commonly accepted standard to define optional arguments only at the end.

If you want to be more specific about which arguments should be set with a large number of optional parameters, you can also use keyword arguments. Since you have to specify the name of the arguments when calling the method here, the order of mandatory and optional keyword arguments doesn't matter.

Optional parameter and Symbol

The ternary operator expects a ?

self.homepage_image.url.blank? ? "something" : "something else"

Also, there is a syntax error in this line

image_tag project.homepage_image_url(format) :alt => html_escape(project.name)

It should be

image_tag project.homepage_image_url(format, :alt => html_escape(project.name))


Related Topics



Leave a reply



Submit