ActiveRecord Model将数据库视图的字段视为整数而不是布尔值

时间:2017-11-01 19:02:29

标签: ruby-on-rails activerecord

我有一个数据库视图,我已链接到ActiveRecord模型。当我调用模型AdherenceActivity.all时,它返回

[
    [0] #<AdherenceActivity:0x007fec986b5328> {
        :adherence_date => Wed, 01 Nov 2017,
            :patient_id => 10000,
               :morning => 0.0,
             :afternoon => 1.0,
               :evening => 1.0,
                 :night => nil
    }
]

它不会将10解释为truefalse。如何更新模型以返回布尔值而不是1.00.0

修改

为了澄清,这是一个数据库视图,而不是一个表。这是我对DB View(Oracle SQL)的迁移

class CreateAdherenceActivities < ActiveRecord::Migration[5.0]
  def up
    execute <<-SQL
      CREATE VIEW adherence_activities AS
        SELECT
          adherence_date,
          patient_id,
          sum(case when scheduled_time = 'morning'   then nvl2(acknowledged_at,1,0) end) as morning,
          sum(case when scheduled_time = 'afternoon' then nvl2(acknowledged_at,1,0) end) as afternoon,
          sum(case when scheduled_time = 'evening'   then nvl2(acknowledged_at,1,0) end) as evening,
          sum(case when scheduled_time = 'night'     then nvl2(acknowledged_at,1,0) end) as night
        FROM medication_adherences
        GROUP BY adherence_date, patient_id
    SQL
  end

  def down
    execute "DROP VIEW adherence_activities"
  end
end

Rails 5.1,Ruby 2.4.1

2 个答案:

答案 0 :(得分:0)

由于没有回应,我会给出我的2。我认为我会这样做的方法是在Classes类本身中添加定义,然后像这样使用getter / setter ..

class AdherenceActivity < ApplicationRecord

  def morning
    #do nothing if nil
    return if @morning.nil?
    #convert to boolean
    @morning.to_bool
  end

  def morning=(val)
    super(val.to_f)
  end
  #And repeat for other boolean values...

end

class FalseClass; def to_f; 0.0 end end
class TrueClass; def to_f; 1.0 end end
class Float; def to_bool; not self.zero? end end 
#NOTE: I am unsure what data type the DB/Rails is setting the 1s and 0s to
#But it looks like a float

'true'和'false'在Ruby中有自己独立的类。这样做是在每个类的末尾添加一个新方法(to_f),在'false'类的情况下只返回0.0,在'true'类的情况下返回1.0。

为了更直观的解释, 在irb:

irb(main):001:0> false.class
=> FalseClass
irb(main):002:0> true.class
=> TrueClass
irb(main):008:0> false.to_f
=> 0.0
irb(main):009:0> true.to_f
=> 1.0

然后,就从float返回到boolean的转换而言,将一个类添加到Float,它将检查它是否为零。 (0.zero?== true所以需要相反的,例如。不是0.zero?)



额外信用:
我建议添加所述的方法,因为当你开始涉及更复杂的情况时,它会使事情变得干燥,简短和甜蜜 假设你有很多不同的布尔值要转换。

class AdherenceActivity < ApplicationRecord
  #Your list of boolean/float columns
  %w[morning afternoon evening night].each do |s|
    #Getter methods
    define_method(s) do
      #do nothing if nil value received
      return if self.instance_variable_get("@#{s}").nil?
      #Get the instance variable with name, eg. @night
      self.instance_variable_get("@#{s}").to_bool
    end
    #Setter methods
    define_method("#{s}=") do |val|
      super(val.to_f)
    end
  end

end

class FalseClass; def to_f; 0.0 end end
class TrueClass; def to_f; 1.0 end end
class Float; def to_bool; not self.zero? end end
#Assuming float data type

希望这有用。

答案 1 :(得分:0)

这与@ brad-ax发布的内容基本相同,但处理nil案例。我希望在ActiveRecord / Query级别上解决这个问题,因为这不会更改查询的返回值,但会更改我在上午/下午/傍晚/晚上调用对象时返回的值。

我选择@ brad-ax是因为这是正确的做法,但为了清晰起见,我想发布我的解决方案。

  def morning
    return if super.nil?
    super == 1
  end

  def afternoon
    return if super.nil?
    super == 1
  end

  def evening
    return if super.nil?
    super == 1
  end

  def night
    return if super.nil?
    super == 1
  end