如何为Jbuilder模板可选字段设置默认值及解决方法调用错误
在Jbuilder模板中为可选字段设置默认值时遇到方法未定义错误
问题背景
我有一个使用Jbuilder模板的RESTful端点,原本的模板代码是这样的:
json.extract! tab_community, :id, :name, :ref_community_type_id, :created_at, :updated_at, :num_of_accounts, :platform_name json.url tab_community_url(tab_community, format: :json)
我想让num_of_accounts和platform_name这两个可选字段在模型未返回对应值时显示默认值,于是尝试修改模板为:
if tab_community.num_of_accounts.nil? json.extract! tab_community, :id, :name, :ref_community_type_id, :created_at, :updated_at, num_of_accounts: 0, platform_name: 'Twitter' else json.extract! tab_community, :id, :name, :ref_community_type_id, :created_at, :updated_at, :num_of_accounts, :platform_name end json.url tab_community_url(tab_community, format: :json)
结果触发了Rails服务器错误:
ActionView::Template::Error (undefined method `num_of_accounts' for #<TabCommunity:0x0000000be66f08>): 1: if tab_community.num_of_accounts.nil? 2: json.extract! tab_community, :id, :name, :ref_community_type_id, :created_at, :updated_at, num_of_accounts: 0, platform_name: 'Twitter' 3: else 4: json.extract! tab_community, :id, :name, :ref_community_type_id, :created_at, :updated_at, :num_of_accounts, :platform_name
错误原因分析
这个错误很直白:你的TabCommunity模型根本没有定义num_of_accounts这个属性或方法——不管是数据库里的物理字段,还是模型中定义的虚拟属性/方法,都不存在。所以直接调用tab_community.num_of_accounts时,Rails找不到对应的方法,直接抛出了undefined method错误,根本到不了判断nil?的那一步。
解决方案
根据这两个字段的实际情况,我给你几种不同的解决思路:
1. 如果这两个是虚拟属性(数据库无对应字段)
如果num_of_accounts和platform_name不是数据库字段,只是你在业务中用到的虚拟属性,那先在模型里定义它们并设置默认值:
# app/models/tab_community.rb class TabCommunity < ApplicationRecord # 定义虚拟属性 attr_accessor :num_of_accounts, :platform_name # 重写方法,返回默认值如果属性为空 def num_of_accounts @num_of_accounts || 0 end def platform_name @platform_name || 'Twitter' end end
之后Jbuilder模板就可以回到最开始的写法,不用写复杂的条件判断:
json.extract! tab_community, :id, :name, :ref_community_type_id, :created_at, :updated_at, :num_of_accounts, :platform_name json.url tab_community_url(tab_community, format: :json)
2. 如果这两个是数据库可选字段(允许为NULL)
如果数据库里确实有这两个字段,但允许为空,那可以用try方法避免方法不存在的错误,或者先判断模型是否响应这个方法:
方法A:用try简化写法
try方法会在对象响应对应方法时调用它,否则返回nil,之后我们再用||设置默认值:
# 先提取必填字段 json.extract! tab_community, :id, :name, :ref_community_type_id, :created_at, :updated_at # 单独处理可选字段,设置默认值 json.num_of_accounts tab_community.try(:num_of_accounts) || 0 json.platform_name tab_community.try(:platform_name) || 'Twitter' # 加上URL字段 json.url tab_community_url(tab_community, format: :json)
方法B:显式判断方法是否存在
如果你想更严谨,可以先判断模型是否有这个方法:
json.extract! tab_community, :id, :name, :ref_community_type_id, :created_at, :updated_at # 处理num_of_accounts if tab_community.respond_to?(:num_of_accounts) json.num_of_accounts tab_community.num_of_accounts || 0 else json.num_of_accounts 0 end # 处理platform_name if tab_community.respond_to?(:platform_name) json.platform_name tab_community.platform_name || 'Twitter' else json.platform_name 'Twitter' end json.url tab_community_url(tab_community, format: :json)
3. 用Jbuilder的merge语法简化代码
如果字段比较多,不想一个个写,可以用merge来合并模型属性和默认值:
# 定义默认值 default_values = { num_of_accounts: 0, platform_name: 'Twitter' } # 提取模型中的必填字段 model_attrs = tab_community.attributes.slice('id', 'name', 'ref_community_type_id', 'created_at', 'updated_at') # 把字符串键转为符号键,方便合并 model_attrs = model_attrs.transform_keys(&:to_sym) # 合并属性和默认值,优先使用模型的非空值 json.merge!(model_attrs.merge(default_values)) do |json, key, default_val| json.set! key, tab_community.respond_to?(key) ? (tab_community.send(key) || default_val) : default_val end json.url tab_community_url(tab_community, format: :json)
内容的提问来源于stack exchange,提问作者goterpsgo
相关产品推荐
相关产品推荐

