简体   繁体   中英

Rails/Rspec respond_to a method_missing lookup

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.

  1. 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 .

  2. Generate your access methods when setting request_params (meta-programming your accessors).

  3. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM