Complexity aliasing `is_x?` To `has_role? x`

Each user has many roles; to find out if the user has the "admin" role, we can use the method has_role?:

some_user.has_role?('admin')

Which is defined as follows:

def has_role?(role_in_question)
  roles.map(&:name).include?(role_in_question.to_s)
end

I would like to write some_user.has_role?('admin')how some_user.is_admin?, so I did:

  def method_missing(method, *args)
    if method.to_s.match(/^is_(\w+)[?]$/)
      has_role? $1
    else
      super
    end
  end

This works fine for the case some_user.is_admin?, but crashes when trying to call it on a user specified in a different association:

>> Annotation.first.created_by.is_admin?
NoMethodError: undefined method `is_admin?' for "KKadue":User
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_proxy.rb:215:in `method_missing'
    from (irb):345
    from :0

What gives?

+3
source share
2 answers

Rails checks if you are up respond_to? "is_admin?"to running send.

So, you need to specialize respond_to?also as:

def respond_to?(method, include_private=false)
  super || method.to_s.match(/^is_(\w+)[?]$/)
end

. , respond_to? , send, .

: (Ruby 1.9.2+) - respond_to_missing?, - :

def respond_to_missing?(method, include_private=false)
  method.to_s.match(/^is_(\w+)[?]$/)
end

unless 42.respond_to?(:respond_to_missing?) # needed for Ruby before 1.9.2:
  def respond_to?(method, include_private=false)
    super || respond_to_missing?(method, include_private)
  end
end
+3

ActiveRecord::Associations::AssociationProxy method_missing , , .

, AP , respond_to? , .

, Rails:

is_ * , . - :

class User
  Role.all.each do |role|
    define_method "is_#{role.name}?" do
      has_role?(role.name)
    end
  end
end

User ,

User.find(Annotation.first.user_id).is_admin?

.

+2

Source: https://habr.com/ru/post/1755828/


All Articles