Search code examples
ruby-on-railsrubycompilationexecutionpundit

Ruby loads the methods at run time or compile?


I'm working on a platform and they asked me to integrate the Pundit gem. When creating a policy I realized that many methods had the same access control policy. Example:

Action1: Only accessible by the administrator or owner of the resource
Action2: Only accessible by the administrator or owner of the resource
Action3: Only accessible by the administrator or owner of the resource
.
.
.

Then I thought about creating dynamic methods in the following way

[: Action1 ?,: Action2? ,: Action3?].each do |meth|
     define_method(meth){@current_user.admin? or @current_user.owner_resource?}
end

But I got a question: Does Ruby on Rails execute the methods at run time or at compile time? Is it optimal to create dynamic methods or is it better to create 3 methods separately in a static way?

Thanks!!!


Solution

  • Does Ruby on Rails execute the methods at run time or at compile time?

    Runtime.

    Methods will be parsed when first interpreted, but the actual code does not get evaluated until it is run.

    A method definition could contain complete nonsense (e.g. undefined variables) - but unless it contains a syntax error, this won't get exposed until the code is actually invoked.

    ...And this is purely a "ruby" thing; it happens regardless of whether or not you're using the rails framework.

    Is it optimal to create dynamic methods or is it better to create 3 methods separately in a static way?

    The depends what you mean by "optimal".

    Performance-wise, it's slightly faster to static methods. But unless you're building a core library, the difference is negligible - so I wouldn't worry about that.

    However, there are other good reasons to define methods statically when possible. Namely: The code is less confusing, it's easier to navigate to method definitions (e.g. when using an IDE), and it's easier to change method definitions when there's less meta-programming.

    Personally, I would probably be inclined to define these methods as:

    def action1?
      user.admin? || user == record.owner
    end
    
    def action2?
      action1?
    end
    
    def action3?
      action1?
    end
    

    (But without knowing what the actions actually are, or how they fit into the wider context of your application, it's hard to give concrete advice.)

    Or if you prefer, you could also use alias.