【问题标题】:Most elegant way to create hash from two datasource从两个数据源创建哈希的最优雅方式
【发布时间】:2019-03-25 05:15:38
【问题描述】:

我有一个 building_table 和 api::building_table,我希望将 building_table 中的数据作为默认值,但如果 building_table 中不存在数据,我希望必须在 api::building_table 中获取它。 问题是 building_table 中可能不存在但 api building_table 中存在的属性。每个表中还有不同名称的列。

这是我的示例代码

def get_building_info
  building = Building.find_by(id: params[:id])
  api_building = Api::Building.find_by(id: params[:id])
  building_hash = {}
  building_hash[:name] = building.name || api_building.name
  building_hash[:room] = building.room || api_building.room
  building_hash[:rent] = building.rent || api_building.monthly_fee
...
end

有没有更优雅的方式来做到这一点?顺便说一句,这是在我的控制器中。

【问题讨论】:

  • 我认为有人建议了一些“聪明”的解决方案,但您的方法易于阅读和理解,您应该坚持下去。

标签: ruby-on-rails ruby ruby-on-rails-4


【解决方案1】:

通用方法,接受键列表作为参数:

def get_building_info(keys = %i[name room rent].zip(%i[name room fee]))
  building = Building.find_by(id: params[:id])
  api_building = Api::Building.find_by(id: params[:id])
  keys.map do |key, api_key|
    [
      key,
      building.attributes[key.to_s] || api_building.attributes[api_key.to_s]
    ]
  end.to_h
end

【讨论】:

  • 我的问题似乎缺少更多细节,对不起!
  • 我也想过,但我有不同名称的表列。很抱歉我没有在我的问题中包含它!
  • 更新了答案。
  • 我不接受 get_building_info 参数的原因是因为它是一个 ajax 查询,所以我只有 id 作为构建参数。
  • 我不确定我是否遵循。上面的方法完全符合您的要求,并且可以在不传递任何参数的情况下完美地调用它。如您所见,它有一个参数的默认值。
【解决方案2】:

可能存在许多解决方案来实现这一点,但是,这里有一个更简单的解决方案:

def get_building_info
  building = Hash.new
  building[:name], building[:room] = desired_building.name, desired_building.room 
end

private

 def desired_building
    Building.find_by(id: params[:id]) || 
    Api::Building.find_by(id: params[:id])
 end

【讨论】:

  • 问题是某个属性可能会从api构建中获取,但这并不意味着其他属性也会从api构建中获取。
  • 你没有收到关于OP的问题
【解决方案3】:

我认为您以正确的方式执行此操作,但 building 变量将被覆盖,您需要定义一个新变量,例如 building2 = {}

【讨论】:

  • 你没有收到关于OP的问题
  • 对不起,我刚刚在浏览器中输入了它,这是一个错字!
【解决方案4】:
before_action :find_records, only: :get_building_info

def get_building_info
  building_hash = {}
  building_hash[:name] = building_name
  building_hash[:room] = building_room
  # OR
  building_hash[:name], building_hash[:room] = building_name, building_room

end

private

def find_records
  @building = Building.find_by(id: params[:id])
  @api_building = Api::Building.find_by(id: params[:id])
end

def building_name
  @building.name || @api_building.name
end

def building_room
  @building.room || @api_building.room
end

【讨论】:

  • 嗨,谢谢你的回答。我的建筑模型由大约 12 根柱子组成,你认为将 12 根柱子放在私人上是一个好习惯吗?
  • 不,不是,。我以为你只有 2 个参数
  • 为什么不呢?您可能很容易生成所有这些方法,因此所有 12 种方法都需要 5 行代码。
  • @AlekseiMatiushkin 但有 12 种私有方法,我认为您的解决方案比我的要好得多。
【解决方案5】:

你可以使用Enumerable#each_with_object:

attrs = [ %i[name name], %i[room room], %i[rent monthly_fee] ]
attrs.each_with_object({}) do |(name, alias_name), h|
  h[name] = building[name] || api_building[alias_name]
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    • 2012-03-05
    • 2012-06-08
    • 2010-09-29
    • 1970-01-01
    • 1970-01-01
    • 2016-02-27
    相关资源
    最近更新 更多