Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails render json including methods with parameters

I have this render in a method controller:

render :json => @boats, :include => {:port => {:only => [:id, :name], :include => {:city => {:only => [:id, :name], :methods => :translatedCity}}}}

but translatedCity method in the model should accept language parameter.

  def translatedCity     
    language = params[:language]
    puts "translatedCity.language=" + language  
    city = TranslationService.translateCity(self.city_id, language)        
    return city.element_translation
  end

I have the parameter in the controller. Is there any way to pass this parameter to the method in the model?

like image 920
Rober Avatar asked May 22 '15 15:05

Rober


3 Answers

Unfortunately the process of passing methods that require params to_json is not nicely built into rails. a typical pattern is to modify the as_json method on the model to accept custom keys, and then calling to_json (or render :json)

# city.rb model
def translatedCity(language)
  puts "translatedCity.language=" + language  
  city = TranslationService.translateCity(self.city_id, language)        
  return city.element_translation
end

def as_json(options = {})
  json_to_return = super
  if options.has_key? :translatedCity
    city_translation = self.translatedCity(options[:translatedCity][:language])
    json_to_return[:translatedCity] = city_translation
  end

  return json_to_return
end

now in your controller you pass everything in accoringdly

render :json => @boats, 
  :include => {
    :port => {
      :only => [:id, :name], 
      :include => {
        :city => {
          :only => [:id, :name], 
          :translatedCity => params[:language]
        }
      }
    }
  }
like image 163
PhilVarg Avatar answered Oct 05 '22 19:10

PhilVarg


All answers are good!

I just did something like:

In controller:

boat.port.language = params[:language]

In model:

attr_accessor :language
  @language  

  def translatedCity            
    city = TranslationService.translateCity(self.city_id, language)        
    return city.element_translation
  end

What do you think?

like image 29
Rober Avatar answered Oct 05 '22 21:10

Rober


as_json doesn't support methods that require arguments, but this is a good place to use a Presenter (or Decorator, or View Model, depending who you talk to) that builds the JSON you want. Draper is a gem that helps with that if you want one, and your controller would look something like

data = @boats.map do |boat|
  BoatPresenter.new(boat).as_json(language: params[:language])
end
render json: data

Then BoatPresenter would add the extra data you want in its as_json:

def as_json(options = {})
  @boat.as_json(options).tap do |json|
    json[:translated_city] = @boat.translated_city(options[:language])
  end
end

You can also have BoatPresenter add your default includes, etc. if you want a standard set without the controller having to worry about it. And if you don't want to do the array mapping yourself, Draper also offers collection presenters (eg BoatsPresenter).


If you're averse to adding a class, you could also override as_json directly on Boat to handle a language option:

def as_json(options = {})
  super(options).tap do |json|
    json[:translated_city] = translated_city(options[:language])
  end
end
like image 27
Kristján Avatar answered Oct 05 '22 19:10

Kristján