Rails:覆盖as_json的动态价值 - 有更聪明的方法吗?

Tom*_*son 12 json ruby-on-rails

我想输出会员链接列表,每个链接都标记为标识当前用户.它在HTML中很简单,但我们正在编写API,因此输出是JSON.

我有它工作,但它似乎过于复杂.这是最好的方法吗?

我的模型AffiliateLink包含一个字段(链接的原始HTML),我将通过添加令牌动态转换和输出.我有一个产生替换的模型方法 - 它是非平凡的,因为我们使用多个附属公司,每个都有一个特殊的转换规则,这个方法知道:

def link_with_token(user_token)
  # some gnarly code that depends on a lot of stuff the model knows
  # that returns a proper link
end
Run Code Online (Sandbox Code Playgroud)

为了在JSON中获取正确的链接html,我做了以下事情:

  • 添加attr_accessor :link_html到模型
  • 添加实例方法以设置新的访问者

...

def set_link_html(token)
  self.link_html = link_with_tracking_token(token)
end
Run Code Online (Sandbox Code Playgroud)
  • as_json在模型中覆盖,用link_html替换原始的html_code

...

def as_json(options = {})
  super(:methods => :link_html, :except => :html_code)
end
Run Code Online (Sandbox Code Playgroud)
  • 迭代控制器方法中返回的集合以进行转换

...

def index
  @links = Admin::AffiliateLink.all  # TODO, pagination, etc.

  respond_to do |format|
    format.html # index.html.erb
    format.json do
      @links.each do |link|
        link.set_link_html(account_tracking_token)
      end
      render json: @links
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这似乎要做很多事情才能完成我的teensy-weensy转换.有用的建议(与此问题有关,而不是代码的其他方面,现在正在变化)是受欢迎的.

anx*_*ety 18

1)迅速解决您的问题(如证明这里):

affiliate_links_controller.rb

def index
  @links = Admin::AffiliateLink.all  # TODO, pagination, etc.

  respond_to do |format|
    format.html # index.html.erb
    format.json do
      render json: @links.to_json(:account_tracking_token => account_tracking_token)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

AffiliateLink.rb

# I advocate reverse_merge so passed-in options overwrite defaults when option
# keys match.
def as_json(options = {})
  json = super(options.reverse_merge(:except => :html_code))
  json[:link_with_token] = link_with_token(options[:account_tracking_token])
  json
end
Run Code Online (Sandbox Code Playgroud)

2)如果您真的在编写API,那么这是一个更具核心的解决方案:

  1. 请参阅此文章描述您的问题.
  2. 查看作者作为解决方案制作的gem.
  3. 使用gem 查看此railscast.

3)最后,方便的解决方案.如果你有一个方便的模型关系,这是干净的:

假装AffiliateLink belongs_to :user.并假设user_token是User的可访问属性.

AffiliateLink.rb

# have access to user.user_token via relation
def link_with_token
  # some gnarly code that depends on a lot of stuff the model knows
  # that returns a proper link
end

def as_json(options = {})
  super(options.reverse_merge(:methods => :link_with_token, :except => :html_code))
end
Run Code Online (Sandbox Code Playgroud)

affiliate_links_controller.rb

def index
  @links = Admin::AffiliateLink.all  # TODO, pagination, etc.

  respond_to do |format|
    format.html # index.html.erb
    format.json do
      render json: @links
    end
  end
end
Run Code Online (Sandbox Code Playgroud)