I know some of you are already doubting my sanity with this. I have a ActiveRecord
class that uses method missing to dig inside a JSON attribute it has.
# app/models/request_interactor.rb
...
def method_missing(method_sym, *arguments, &block)
return self.request_params[method_sym.to_s] if self.request_params[method_sym.to_s]
super
end
the test looks like this
before(:each) do
@ri = RequestInteractor.create(result: {magic_school: true, magic_learnt: 'all things magical'}, request_params: {application_id: 34, school_id: 20, school_name: 'Hogwarts', course_name: 'Defence against the Dark Arts.'})
end
it 'should respond to attributes set in the request parameters' do
expect(@ri).to respond_to(:school_name)
expect(@ri.school_name).to eq('Hogwarts')
end
I tried binding inside the test, the @ri.school_name
will eq 'Hogwarts'
, but when it runs the responds_to
it will fail saying there is no such a method! The dirty, dirty liar!
I tried doing something like this in the model:
def respond_to?(method, include_private = false)
super || self.respond_to?(method, include_private)
end
But this will return a stack level too deep, because of recursion, because of recursion.. so now the fate of my day is in your hands! Enlighten me O' great ones. how would I test the respond to of the method missing.
Use respond_to_missing
. More infos here .
Now, with all this being said. Your pattern will still look hackish if you ask me.
Refactors
Ruby has tons of way to clean this.
Use a delegation pattern
delegate :method_name, :to => :request_params
(check other options in doc). This should solve your problems by having a method in your object so respond_to?
will work and you will avoid overriding method_missing
.
Generate your access methods when setting request_params
(meta-programming your accessors).
Use OpenStruct since these can be initialized with a Hash
such as your request_params
. If you add delegation on top, you should be cool.
Hope this helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.