June 10, 2019
This blog is part of our Rails 6 series.
Rails 6 adds :private option to
delegate
method. After this addition, we can delegate methods in the private scope.
Let's checkout how it works.
Let's create two models named as Address and Order. Let's also delegate
validate_state method in Order to Address.
class Address < ApplicationRecord
validates :first_name, :last_name, :state, presence: true
DELIVERABLE_STATES = ['New York']
def validate_state
unless DELIVERABLE_STATES.include?(state)
errors.add(:state, :invalid)
end
end
end
class Order < ApplicationRecord
belongs_to :address
delegate :validate_state, to: :address
end
>> Order.first
SELECT "orders".* FROM "orders"
ORDER BY "orders"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> #<Order id: 1, amount: 0.1e2, address_id: 1, created_at: "2019-03-21 10:02:58", updated_at: "2019-03-21 10:17:44">
>> Address.first
SELECT "addresses".* FROM "addresses"
ORDER BY "addresses"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> #<Address id: 1, first_name: "Amit", last_name: "Choudhary", state: "California", created_at: "2019-03-21 10:02:47", updated_at: "2019-03-21 10:02:47">
>> Order.first.validate_state
SELECT "orders".* FROM "orders"
ORDER BY "orders"."id" ASC LIMIT $1 [["LIMIT", 1]]
SELECT "addresses".* FROM "addresses"
WHERE "addresses"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
=> ["is invalid"]
Now, let's add private: true to the delegation.
class Order < ApplicationRecord
belongs_to :address
delegate :validate_state, to: :address, private: true
end
>> Order.first.validate_state
SELECT "orders".* FROM "orders"
ORDER BY "orders"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> Traceback (most recent call last):
1: from (irb):7
NoMethodError (private method 'validate_state' called for #<Order:0x00007fb9d72fc1f8>
Did you mean? validate)
As we can see, Rails now raises an exception of private method called if
private option is set with delegate method.
Here is the relevant pull request.
If this blog was helpful, check out our full blog archive.