Positional and Keyword Arguments in Ruby on Rails

Method parameters can be passed in different ways, allowing for flexible and readable code. Understanding the difference between positional arguments and keyword arguments is essential for writing clean and maintainable code.

To illustrate how these types of arguments can be used in practice, we’ll take a look at an example using an initialize method. This example will help clarify the distinction between positional arguments and keyword arguments in the context of a class constructor. While this initializer serves as a concrete example, the concepts apply broadly across Ruby methods.

Let’s break down these two types of arguments using the following example of an initialize method:

1
2
3
4
5
6
7
def initialize(plan, user, params = {}, current_country: nil)
  @plan = plan
  @user = user
  @params = params
  @current_country = current_country || user&.current_country
  @plan_price_resolver = PlanPriceResolver.new(@plan, user, current_country: @current_country)
end

1. Positional Arguments

Positional arguments must be provided in a specific order when calling the method. In this example, plan, user, and params are positional arguments.

plan: The first argument passed to the method. It is assigned directly to the instance variable @plan. user: The second argument passed and assigned to @user. params = {}: This is an optional argument with a default value. In this case, it defaults to an empty hash ({}). The params hash is a great way to pass multiple values through a single argument.

Example of a method call using positional arguments:

1
   Membership::Plan::BasePresenter.new(plan, user, { location_id: 1, volunteer_position_id: 2 })

Here, params will receive { location_id: 1, volunteer_position_id: 2 }.

2. Keyword Arguments

Keyword arguments are named parameters that do not need to follow a strict order when passed to a method. They are introduced with a name followed by a colon (:), and they can have default values, such as current_country: nil.

current_country: nil: This is a keyword argument. If not provided, it will default to nil. In the method, it is assigned as @current_country = current_country || user&.current_country. This means that if current_country is not passed, it will fall back to the country associated with the user.

Example of a method call using keyword arguments:

1
   Membership::Plan::BasePresenter.new(plan, user, { location_id: 1 }, current_country: "Brazil")

In this example, current_country is explicitly passed as “Brazil”. This overwrites the default value of nil.

The Difference Between Positional and Keyword Arguments

Practical Example

Imagine you have two users: one who has a country already set and another without. You want to initialize a presenter object for both users, optionally passing the current_country value when it’s not present.

Case 1: User without a current_country (you pass it explicitly):

1
presenter = Membership::Plan::BasePresenter.new(plan, user, { location_id: 1 }, current_country: "Brazil")

Here, you’re explicitly setting current_country to “Brazil” when initializing the presenter.

Case 2: User with a current_country (you don’t pass it explicitly):

1
presenter = Membership::Plan::BasePresenter.new(plan, user, { location_id: 1 })

In this case, since current_country is not passed as an argument, the method will use the value from the user object (user&.current_country).

Why Use Keyword Arguments?

Keyword arguments offer several advantages:

Positional arguments are great when the order matters and you need a fixed structure. Keyword arguments, on the other hand, offer more flexibility and clarity, especially when there are many optional or default values involved.

Let me know if you need further adjustments!