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
json
response. - it relies on controller name find instance variable (
/posts
converted@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