【问题标题】:save! does not save updated value object when using Serializer节省!使用 Serializer 时不保存更新的值对象
【发布时间】:2019-04-29 19:13:20
【问题描述】:

我有一个 events 对象,它是 ruby​​ 中哈希的包装器。我用它来存储已经发生和尚未发生的事件。信息包括计划日期、实际日期事件类型、事件类型等。

我使用 Active Record 中的序列化方法来加载事件对象。它在 posgresql 中以 jsonb 的形式存储。

当我调用保存时!或 update_attribute ,它不会向其添加新的转运事件 但是当我调用 update_column 时,它会产生所需的结果。

这是我更新事件的代码

    serialize :events, Shipload::Events::Serializer

    def add_transshipment_event
      self.events.add_transshipment
      # update_column(:events, self.events)
      update_attribute(:events, self.events)
      # save!
    end

这里是 events.rb

class Shipload
class Events

attr_reader :events

# Takes a hash of events
#
# @param [Hash]
def initialize(events)
  unless events.present?
    events = {}
    events[Shipload::Events::Event::GATE_IN_EVENT_KEY] = Shipload::Events::Event.new(event_type: Shipload::Events::Event::GATE_IN)
    events[Shipload::Events::Event::ORIGIN_DEPARTURE_EVENT_KEY] = Shipload::Events::Event.new(event_type: Shipload::Events::Event::ORIGIN_DEPARTURE)
    events[Shipload::Events::Event::ARRIVAL_EVENT_KEY] = Shipload::Events::Event.new(event_type: Shipload::Events::Event::ARRIVAL)
    events[Shipload::Events::Event::GATE_OUT_EVENT_KEY] = Shipload::Events::Event.new(event_type: Shipload::Events::Event::GATE_OUT)
  end
  @events = events
end

# Takes in the event has received from HTTP request and translates it into {Shipload::Events} object
#
# @param events_hash [Hash]
# @return [Shipload::Events]
def self.parse(events_hash)
  events_hash = events_hash["events"]
  events = {}
  events_hash.keys.each do |key|
    event = events_hash[key]
    event["mode"] = event["mode"].present? ? event["mode"].to_i : nil
    event["planned_date"] = event["planned_date"].present? ? event["planned_date"].to_datetime : nil
    event["original_planned_date"] = event["original_planned_date"].present? ? event["original_planned_date"].to_datetime : nil
    event["actual_date"] = event["actual_date"].present? ? event["actual_date"].to_datetime : nil
    event["event_type"] = event["event_type"].present? ? event["event_type"].to_i : nil
    events[key] = Shipload::Events::Event.new(Util.to_h_with_symbol_keys(event))
  end
  new(events)
end

# Returns total number of events
#
# @return [Integer]
def count
  @events.count
end

# Returns the arrival event if present, nil otherwise
#
# @return [Shipload::Events::Event]
def arrival_event
  @events[Shipload::Events::Event::ARRIVAL_EVENT_KEY]
end

# Returns event identified by key
#
# @param key [String/ Float]
# @return [Shipload::Events::Event]
def [](key)
  @events[key.to_s]
end

# Assigns Event to the key in events
#
# @param key [String/ Float]
# @return [Shipload::Events::Event]
def []=(key, event)
  @events[key.to_s] = event
end

# Returns all the values of @events hash
#
# @return [Array]
def values
  @events.values
end

# Returns all the keys in @events hash
#
# @return [Array]
def keys
  @events.keys.sort
end

# # Returns the Events object in hash format
# #
# @return [Hash]
def to_h
  @events.to_h
end

# Adds a transhipment arrival and departure event.
def add_transshipment
  add_trans_arrival_event
  add_trans_departure_event
end

# Deletes latest transhipment arrival and departure event.
def delete_transshipment
  sorted_transshipment_keys = @events.keys.sort[2..-3]
  2.times do
    @events.except!(sorted_transshipment_keys.last) if sorted_transshipment_keys.present?
    sorted_transshipment_keys -= [sorted_transshipment_keys.last]
  end
end

# Returns the current event. The most latest event with actual date set is current event
#
# @return [Event]
def current_event
  keys.sort.reverse.each do |key|
    return self.events[key] if self.events[key].actual_date.present?
  end
  nil
end

# Returns the next event. It is the event after current event. In case of current_event being nil,
# it returns first event.
#
# @return [Event]
def next_event(current_event)
  current_event.nil? ? @events.first.last : @events[keys[keys.index(@events.key(current_event)) + 1]]
end

# Sorts the events on basis of keys
def sort_on_keys!
  @events = @events.sort.to_h
end

# Returns total events present
#
# @return [Integer]
def total_events
  @events.length
end

# Returns total events yet to occur
#
# @return [Integer]
def pending_events
  total_events - completed_events
end

# Returns total events which have occured
#
# @return [Integer]
def completed_events
  keys.index(@events.key(current_event)).present? ? keys.index(@events.key(current_event)).to_i + 1 : 0
end

private

# Returns the next key to be
def generate_transshipment_event_key
  key = @events.keys.sort[2..-3].last || Shipload::Events::Event::TRANS_SHIPMENT_MASTER_KEY
  integer_part, fraction_part = key.split(".")
  fraction_part = fraction_part.to_i + Shipload::Events::Event::TRANS_SHIPMENT_KEY_STEP
  integer_part+"."+format("%02d",fraction_part)
end

def add_trans_arrival_event
  key = generate_transshipment_event_key
  trans_arrival = Shipload::Events::Event.new(event_type: Shipload::Events::Event::TRANS_SHIPMENT_ARRIVAL)
  @events[key] = trans_arrival
end

def add_trans_departure_event
  key = generate_transshipment_event_key
  trans_departure = Shipload::Events::Event.new(event_type: Shipload::Events::Event::TRANS_SHIPMENT_DEPARTURE)
  @events[key] = trans_departure
end

def latest_transshipment_event
  @events[@events.keys.sort[2..-3].last] || nil
end
end
end

serializer.rb

class Shipload
class Events
class Serializer
  # Translates events object to format which can be stored in DB
  #
  # @param [Shipload::Events]
  # @return [Hash]
  def self.dump(events)
    byebug
    events.to_h
  end

  def self.load(events_h)
    events = {}
    if events_h.present?
      events_h.each do |key, value|
        %w(planned_date actual_date original_planned_date).each do |date|
          value[date] = value[date].to_datetime unless value[date].nil?
        end
        events[key] = Shipload::Events::Event.new(Util.to_h_with_symbol_keys(value))
      end
    end
    Shipload::Events.new(events)
  end
end
end
end

【问题讨论】:

  • 尝试 update_attributes
  • update_attributes 也不起作用。和 AFAIK,update_attribute 在内部调用 update_attributes
  • 两者有区别。

标签: ruby-on-rails ruby serialization


【解决方案1】:

见文档:https://maxivak.com/update_attribute-and-update_attributes-ruby-on-rails/

查看链接:Rails: update_column works, but not update_attributes

update_column 不验证记录,不调用回调,不调用 save 方法,尽管它确实更新了数据库中的记录。

可能有一些回调限制使用 update_attribute 保存它。

只需使用 update_attributes,因为 update_attributes 会尝试验证记录、调用回调和保存。然后你可以检查错误。

update_attribute 不验证记录,调用回调并保存;

除非您确切知道自己在做什么,否则您应该使用 update_attributes 并避免使用其他两种方法。如果您稍后在模型中添加验证和回调,使用 update_attribute 和 update_column 可能会导致难以调试的不良行为。

【讨论】:

  • 我了解这些方法之间的区别。刚刚意识到有人将 before_create 更改为 before_save。浪费了 2.5 小时
猜你喜欢
  • 1970-01-01
  • 2018-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多