我以JSON对象的形式获得ChromeDriver - WebDriver for Chrome响应,其中一些嵌套数组包含一组联系人详细信息。我想在我的Rails app控制器中创建一个对象,该对象包含响应中的任何信息。我尝试使用像bellow这样的代码来做这件事(注意我使用的宝石允许用点表示法访问对象):
@automatic_profile = AutomaticProfile.new(
profile_id: @profile.id,
first_name: @intel.contact_info.full_name,
email: @profile.email,
gender: @intel.demographics.gender,
city: @intel.demographics.location_deduced.city.name,
skype: @intel.contact_info.chats.select { |slot| slot.client == "skype" }[0].handle),
organization_1: @intel.organizations[0].name if @intel.organizations,
# other similar lines for other organizations
twitter: (@intel.social_profiles.select { |slot| slot.type_name == "Twitter" }[0].url if @intel.social_profiles),
twitter_followers: (@intel.social_profiles.select { |slot| slot.type_name == "Twitter" }[0].followers.to_i) if @intel.social_profiles,
twitter_following: (@intel.social_profiles.select { |slot| slot.type_name == "Twitter" }[0].following.to_i if @intel.social_profiles),
# other similar lines for other social profiles
)
我对此代码有两个问题:
我尝试在每一行添加if语句,如下所示:
twitter: (@intel.social_profiles.select { |slot| slot.type_name == "Twitter" }[0].url if @intel.social_profiles),
但它并不干,我对括号的使用感到困惑,因此我提出了额外的例外情况。
关于创建一个带有嵌套数组响应的大Json数据的对象,您能否就最佳实践提出建议?并建议我如何解决这个特殊情况?
答案 0 :(得分:2)
您可以使用.first
,.try
的组合。 (和.dig
如果你使用的是ruby 2.3),以避免在访问它们时出现异常。
.try
将返回nil。例如:
{ a: 2 }.try(:b) # returns nil
.dig
与.try
类似,但它可以达到多个级别,因此这可能对深度嵌套的级别有用。
[['a'], ['a','b']].dig(0, 1) # first element, then second element - nil
[['a'], ['a','b']].dig(1, 1) # second, then second again - 'b'
{ a: [1, 2] }.dig(:a, 0) # 1
{ a: [1, 2] }.dig(:a, 2) # nil
foo = OpenStruct.new
foo.bar = "foobar"
{ b: foo }.dig(:b, :bar) # 'foobar'
@intel.dig(:contact_info, :full_name)
@intel.dig(:organizations, :first, :name)
对于最后一部分,你也可以用这种方式重构它:
def twitter_profile
return unless @intel.social_profiles.present?
@intel.social_profiles.find { |slot| slot.type_name == "Twitter" }
end
twitter: twitter_profile.try(:url),
twitter_followers: twitter_profile.try(:followers).to_i,
twitter_followings: twitter_profile.try(:followings).to_i,
twitter_profile
可能是控制器中的私有方法。如果您发现自己开始拥有太多这些内容,则可以使用服务对象来创建配置文件。
class ProfileCreatorService
def initialize(intel)
@intel = intel
end
def perform
AutomaticProfile.new(...)
end
private
def twitter_profile
return unless @intel.social_profiles.present?
@intel.social_profiles.find { |slot| slot.type_name == "Twitter" }
end
..
end