One of the reasons I don't really use the decorator pattern is having to call .decorate every time I need access to the decorator methods, which is quite often.
Would it be a good practice decorating on method missing, eg:
class User < ApplicationRecord
def foo
"foo!"
end
def method_missing(m, *args, &block)
if UserDecorator.instance_methods.include? m
UserDecorator.new( self ).decorate.send(m, args)
end
end
end
class UserDecorator < WhateverDecorator
def bar
"bar!"
end
end
If it's not a good practice, could you be so kind as to explain why?
Related
Why when I do self.method from a class, I get an undefined method `my_method' for MyModule::MyOtherModule::MyClass:Class
module MyModule
module OtherModule
class MyClass < Base
def my_method
end
def self.my_self_method
my_method
end
end
end
end
I call my_self_method with send from an herited [sic] class:
class Base
class << self
my_method(method_name)
send("my_self_#{method_name}")
end
end
end
I don't understand it.
In your code, you're defining one instance method (my_method), and one class method (my_self_method).
This means you can call:
MyClass.my_self_method
or
MyClass.new.my_method
If you want my_method to be callable from my_self_method, you could define it as:
def self.my_method
...
end
Then the following would be available:
def self.my_self_method
my_method
end
Here's another alternative. There's a comment that suggests it's bad practice to call new.my_method from within a class method, but I've seen a pattern that applies this that I find quite idiomatic, for example:
class MyClass
def self.run(the_variables)
new(the_variables).process
end
def initialize(the_variables)
# setup the_variables
end
def process
# do whatever's needed
end
end
This allows a simple entry point of MyClass.run(the_variables). If your use case seems suitable, a similar pattern for you would be:
module MyModule
module OtherModule
class MyClass < Base
def my_method
end
def self.my_self_method
new.my_method
end
end
end
end
I'm sure there's scope to disagree with this pattern, and would be interested to hear others' opinions in the comments.
Hope this helps clear a few things up #N.Safi.
Is it okay to call a private method of a parent class's subclass from a module which is included in the parent class especially when it concerns ApplicationController, Controllers and lib modules in Rails?
Consider if required to change the controller name the method name to reflect the model name(to Article) change.
I feel this is really bad coding and wanted to know what community thinks about this
Example from a Rails Application:
/lib/some_module.rb
module SomeModule
include SomeModuleResource
def filtering_method
calling_method
end
def calling_method
fetch_object
end
end
/lib/some_module_resource.rb
module SomeModuleResource
def fetch_object
note
end
end
/app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
include SomeModule
before_action :filtering_method
end
/app/controllers/notes_controller.rb
class NotesController < ApplicationController
def show
end
private
def note
#note ||= Note.find(param[:id]))
end
end
I'm of the opinion that this is not necessary bad, although when you expect a certain interface (methods, variables, etc.) from the class that includes the module I would add the following:
module SomeModuleResource
def fetch_object
note
end
private
def note
raise NotImplementedError
end
end
This way, when #note is called without implementing it (because you forgot it was needed or whatever) a NotImplementedError is raised.
Another option is to work around it and create a more general solution. For example, if all controllers behave the same way you described above you can do the following:
module SomeModuleResource
def fetch_object
note
end
private
def note
klass = params[:controller].classify.constantize
instance = klass.find(params[:id])
var_name = "##{klass.underscore}"
instance_variable_set(var_name, instance) unless instance_variable_get(var_name)
end
end
You could also create a class helper method like before_action so that you can pass your own implementation.
module SomeModule
include SomeModuleResource
def self.included(base)
base.extend(ClassMethods)
end
def filtering_method
calling_method
end
def calling_method
fetch_object
end
module ClassMethods
def custom_before_action(&block)
define_method(:note, &block)
private :note
before_action :filtering_method
end
end
end
Now you can use custom_before_filter { #note ||= Note.find(params[:id]) } in every controller (after including).
The above is just to present you with ideas. I'm sure you could find better solution to the problem, but this hopefully points you in the right direction.
See: Alternatives to abstract classes in Ruby?. Or search for abstract classes in Ruby and you'll find more on this subject.
How does one override a class method defined in a model concern?
This is a bit tricky since you’re not really overriding a class method right? Because it’s using the concern api of definining class methods in the class_methods block.
so say I have a concern that looks like this:
module MyConcern
extend ActiveSupport::Concern
class_methods do
def do_something
#some code
end
end
end
In model.. how would I override that method so that I could call it like we do with super when using inheritance? So in my model I’d like to go:
def self.do_something
#call module do_something
end
?
If you've included MyConcern in the model that defines self.do_something, you should just be able to use super:
module MyConcern
extend ActiveSupport::Concern
class_methods do
def do_something
puts "I'm do_something in the concern"
end
end
end
class UsesMyConcern < ActiveRecord::Base
include MyConcern
def self.do_something
super
end
end
UsesMyConcern.do_something
# => "I'm do_something in the concern"
If you haven't or don't want to include MyConcern in the model and you want to invoke do_something on the module without creating any intermediary objects, you can change your model to:
class UsesMyConcern < ActiveRecord::Base
def self.do_something
MyConcern::ClassMethods.instance_method(:do_something).bind(self).call
end
end
UsesMyConcern.do_something
# => "I'm do_something in the concern"
ActiveSupport::Concern.class_methods defines a ClassMethods module in the concern if there isn't one already, and that's where we can find the do_something method.
Why not simply call the module's method: MyConcern.do_something?
I'm not sure if there's an easy of doing super for modules (though I can see why that may be useful).
The next best solution could be doing something like calling #included_modules and manually iterating with #responds_to?:
def self.do_something
self.super_module(__method__)
end
def self.super_module(method)
self.included_modules.find { |m| m.responds_to? method }.public_send(method)
end
The old way using alias_method_chain: https://ernie.io/2011/02/03/when-to-use-alias_method_chain/
The new way (requires > ruby 2.0.0) you really should use this, as there will be a DEPRECATION WARNING when using it in rails 5.0:
http://paweljaniak.co.za/2014/09/30/understanding-ruby-module-prepend-and-include/
I'm new to ruby/rails world, and I'm facing and issue that appears to be something trivial, but it isn't being that easy for me.
What I want to do, is to write a simple helper method, to help keep the controllers clean. This method will receive a symbol/string, and create an instance variable with the camelized received string, which will evaluate to a constant/class.
My attempts resume themselves to this:
class ApplicationController < ActionController::Base
...
protected
def self.service(name)
instance_eval do
instance_variable_set("##{name.to_s.pluralize}", name.to_s.camelize.constantize)
end
end
And, in my controller:
class UserController < ApplicationController
service :user
But when I do this, it create the instance variables in UserController, not UserController.new. So, I know what is wrong, but I couldn't find how can I do this right.
Can anyone help me with that?
The trouble is that this method is in the class scope:
def self.service(name)
instance_eval do
instance_variable_set("##{name.to_s.pluralize}", name.to_s.camelize.constantize)
end
end
This means it'll be setting class level instance variables - or class variables (kinda).
If you want to follow this approach, you'll need to store these all in an array or similar at the class level, which can be read out and turned into instance variables when the class is instantiated.
However, I don't like to mess with the initialize method on controllers. It's not the way to do things, so could change the class behaviour, break things or become fragile when changing versions.
In your ApplicationController, something like:
class << self
def service(name)
#services ||= []
return #services += name.map(&:to_sym) if name.is_a?(Array)
#services << name.to_sym
end
def service_names
#services
end
end
before_action :services
def services
self.class.service_names.each do |name|
instance_eval do
instance_variable_set("##{name.to_s.pluralize}", name.to_s.camelize.constantize)
end
end
end
This is untested.
my ruby (on rails) class looks like:
class Foo
def self.method1
someAction
end
def self.method2
someAction
end
def someAction
//doSmth
end
end
any ideas how to make this work or achieve the same behavior some other way?
thanks!
If some_action is appropriate as a class method, I'd do it like this:
class Foo
def self.method1
some_action
end
def self.some_action
# do stuff
end
def some_action
self.class.some_action
end
end
If method1 is supposed to be a convenience method, then I'd do like Hates_ said to.
class Foo
def self.method1
self.new.some_action
end
def some_action
# do stuff
end
end
The decision for me is usually whether some_action is more of a utility method (like generating a random key, in which case I'd pick the first form), or if it's an entry point to something more complex (like a parser, in which case I'd pick the second form).
You cannot call an instance method from a class method, without an actual instance of the class itself. You can do it as such:
class Foo
def self.method1
myFoo = Foo.new
myFoo.someAction
end
def someAction
//doSmth
end
end