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
How to Print Out the Contents of an Object in Rails for Easy Debugging
Using Instance Variables in Class Methods - Ruby
How to Change All the Keys of a Hash by a New Set of Given Keys
How Can an Activerecord::Relation Object Call Class Methods
How to Fix Rubygems Recent Deprecation Warning
How to Simulate Java-Like Annotations in Ruby
How to Read the Content of an Excel Spreadsheet Using Ruby
Differencebetween Using .Exists, and .Present? in Ruby
How to Add Migration with Multiple References to the Same Model in One Table? Ruby/Rails
How to Validate Exits and Aborts in Rspec
Using a String as a Variable at Run Time
Best Way to Debug Third-Party Gems in Ruby