DateTime对话抛出'无法复制Fixnum'

时间:2014-03-14 20:19:29

标签: ruby-on-rails ruby datetime jruby fixnum

我在Ruby on Rails 4.0上有一个带有jruby 1.7.9的表单。我使用Mongoid而不是ActiveRecord。

当我使用DateTime对象和附件(多部分文件)提交表单时,它会抛出错误“无法复制Fixnum”。应用程序将DateTime对象存储为数据库中的Unix时间戳。

如果我在没有DateTime的情况下提交表单,则会成功保存附件。如果我提交没有附件的表单,它会按预期保存DateTime。当两者都实现时,它会抛出错误。

我该如何解决这个问题?

完整错误消息是:

can't dup Fixnum
Extracted source (around line #222):

220 self.data[name] = DateTime.parse(value).to_time.to_i
221 when 'datetime'
222 self.data[name] = DateTime.parse(value).to_time.to_i
223 when 'time'
224 self.data[name] = DateTime.parse(value).to_time.to_i
225 when 'number'

Rails.root: /Users/mehmetdavut/Documents/
Application Trace | Framework Trace | Full Trace

app/models/content.rb:222:in `change_property_types'
app/models/content.rb:214:in `change_property_types'
app/controllers/contents_controller.rb:56:in `update'

Request

Parameters:

{"utf8"=>"✓",
 "_method"=>"patch",
 "authenticity_token"=>"viv0CO7QKSY8kklTiLAXpdGkqv2W7fiW3Zrf2ZnKjpc=",
 "content"=>{"data"=>{"second_datetime"=>"2014-04-07 17:20:00"},
 "url"=>"",
 "language_id"=>"ffef8bca0000ffd4b4cee70e",
 "device_id"=>"52eeb9964d65682809130000",
 "template_id"=>"fff02c4d0000a37cc11eed8f",
 "layout_id"=>"fff02c760000a37cc11eed90",
 "access"=>{"requires_authentication"=>"0",
 "requires_ssl"=>"0"},
 "discoverability"=>{"title"=>"",
 "description"=>"",
 "keywords"=>"",
 "sitemap_change_frequency"=>"",
 "sitemap_priority"=>"",
 "exclude_from_search"=>"0"},
 "menu"=>{"alias"=>"",
 "class"=>"",
 "passive"=>"0",
 "script"=>"",
 "show_in_navigation"=>"0",
 "show_in_sitemap"=>"0"},
 "taxonomy"=>{"category_id"=>"",
 "tags"=>""},
 "published_at"=>"2014-03-14T12:01:24-08:00",
 "unpublished_at"=>""},
 "attachments"=>{"second_file"=>#<ActionDispatch::Http::UploadedFile:0x162cbfcf @original_filename="Screen Shot 2014-03-13 at 00.38.30.png",
 @headers="Content-Disposition: form-data; name=\"attachments[second_file]\"; filename=\"Screen Shot 2014-03-13 at 00.38.30.png\"\r\nContent-Type: image/png\r\n",
 @tempfile=#<Tempfile:/var/folders/cs/6xmggtv54nq8l2xw77mzhtcr0000gn/T/RackMultipart20140314-18002-csbpyn>,
 @content_type="image/png">},
 "commit"=>"Update Content",
 "page_id"=>"fff02ce20000a37cc11eed96",
 "id"=>"fff02ce20000a37cc11eed97"}

这是“change_property_types”方法:

def change_property_types
  self.data.each do |name, value|
    property = self.page.document.properties.where(name: name).first

    unless value.blank?
      case property.type
      when 'date'
        self.data[name] = DateTime.parse(value).to_time.to_i
      when 'datetime'
        self.data[name] = DateTime.parse(value).to_time.to_i
      when 'time'
        self.data[name] = DateTime.parse(value).to_time.to_i
      when 'number'
        self.data[name] = value.to_i
      when 'file'
        # self.attachments << Attachment.create(file: value)
      else
        self.data[name] = value
      end
    end
  end
end

2 个答案:

答案 0 :(得分:0)

发生此错误是因为value是fixnum。 以下代码的输出是什么?

...
when 'datetime'
  raise value.class.inspect
...

你的表格是什么样的?

如果你这样做会发生什么:

unless value.blank?
    case property.type
    when 'date'
        self.data[name] = DateTime.parse(value.to_s).to_time.to_i
    when 'datetime'
        self.data[name] = DateTime.parse(value.to_s).to_time.to_i
    when 'time'
        self.data[name] = DateTime.parse(value.to_s).to_time.to_i
    when 'number'
        self.data[name] = value.to_i
    when 'file'
        # self.attachments << Attachment.create(file: value)
    else
        self.data[name] = value
    end
end

答案 1 :(得分:0)

您的代码中有很多重复项。这使得它非常密集并且难以追踪您的错误。我可能会这样重构。注意:这是代码未经测试的因素

# DRY up your code :)

def change_property_types
  data.each do |name, value|
    next if value.blank?
    self.data[name] = if get_property_type =~ /file/i
      set_attachments(value)
    elsif value.present? && check_dateishness
      DateTime.parse(value).to_time.to_i
    else
      value
    end
  end
end

private

def check_dateishness 
  %w(date datetime time).include?(get_property_type)
end

# handle the case where attachements may be nil. 
def set_attachements(value)
  if self.attachments.blank?
    self.attachments = [Attachment.create(file: value)] 
  else
    self.attachments << Attachment.create(file: value)
  end
end

# You could probably memoize this... i.e. @some_var ||= ...
def get_property_type
  page.document.properties.where(name: name).first.type
end

或者您可以更多地分解您的代码。

# Or decompose it to better track down errors
...

def change_property_types
  data.each do |name, value|
    next if value.blank?
    if property_type =~ /file/
      # you need to handle the attachments.nil?
      attachments << Attachment.create(file: value)
    else
      data[name] = parse_it(property).to_i
    end
  end
end

private

def property_type
  @property ||= page.document.properties \
    .where(name: name).first.type
end

# Really this case statement can be simplified
# as you could check the class of the object, i.e.
# value.is_a?(Date) or value.is_a?(Time) and since
# the only Ruby class that needs to_time is Date 
# you simplify the code
def parse_it(value)
  case value.type
  when 'time'     then time_parser(value)
  when 'date'     then date_parser(value)
  when 'datetime' then datetime_parser(value)
  else               value
  end
end

def date_parser(date)
  return date.to_time if date.is_a?(Date)
  Date.parse(date.to_s).to_time
end

# Time has a to_i function
def time_parser(time)
  return time if time.is_a?(Time)
  Time.parse(time.to_s)
end

# DateTime has a to_i function
def datetime_parser(datetime)
  return datetime if datetime.is_a?(DateTime)
  DateTime.parse(datetime.to_s)
end

...