i know when using view templates (html, rabl), don't need explicit render call in controller action because default, rails renders template name corresponding controller action name. concept (not caring rendering in controller code) , therefore wonder whether possible when using activemodel::serializers?
example, code generated controller (rails 4.1.0):
class productscontroller < applicationcontroller before_action :set_product, only: [:show, :edit, :update, :destroy] #other actions # /products/1 # /products/1.json def show end end and serializer:
class productserializer < activemodel::serializer attributes :id, :name, :description, :url, :quantity, :price end hitting /products/1.json, expect 2 things happen:
- fields not listed in serializer ommited,
- whole json object incapsulated within 'product' top level field.
however, not happen, whole serializer ignored. if modify show method following:
# /products/1 # /products/1.json def show @product = product.find(params[:id]) respond_to |format| format.html format.json { render json: @product } end end and fine, have lost benefit of before_action filter (and seems me have redundant code).
how should done?
without explicit render or respond_with or respond_to rails matching template. if template not exist rails throws error.
however, can create own resolver bypass this. instance, suppose created app\models\serialize_resolver.rb , put it:
class serializeresolver < actionview::resolver protected def find_templates(name, prefix, partial, details) if details[:formats].to_a.include?(:json) && prefix !~ /layout/ instance = prefix.to_s.singularize source = "<%= @#{instance}.active_model_serializer.new(@#{instance}).to_json.html_safe %>" identifier = "serializeresolver - #{prefix} - #{name}" handler = actionview::template.registered_template_handler(:erb) details = { format: mime[:json], updated_at: date.today, virtual_path: "/#{normalize_path(name, prefix)}" } [actionview::template.new(source, identifier, handler, details)] else [] end end def normalize_path(name, prefix) prefix.present? ? "#{prefix}/#{name}" : name end end and then, in either application controller (or in individual controller) place:
append_view_path ::serializeresolver.new with should able want. if json request, create erb template right content , return it.
limitations:
- this bit clunky because relies on erb, not needed. if have time create simple template handler. can invoke without erb.
- this wipe out default
jsonresponse. - it relies on controller name find instance variable (
/postsconverted@post.) - i've tested little. logic smarter.
notes:
- if template present, used first. allows override behavior.
- you can't create new renderer , register it, because default process doesn't hit it. if template not found, error. if file found, goes straight invoking template handler.
Comments
Post a Comment