18528

[code]

    product = <Item id: 4, url: nil, memo: nil, created_at: "2015-11-07 09:48:36", updated_at: "2015-11-07 09:48:36", Totalweight: 390.0, Perweight: nil, price: 1000>
    attr = {"id"=>4, "tag_list"=>"peanuts", "price"=>1000, "url"=>nil, "Totalweight"=>390, "memo"=>nil}
    
[/code]

で、

[code]

    product.update!(attr)
    
[/code]

ないしは、

[code]

    product.update_attributes!(attr)
    
[/code]

で、activerecordを更新しようとしていますが、

[code]

    SQLite3::ConstraintException　UNIQUE constraint failed: items.id
    !! #<ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraint failed: items.id: INSERT INTO "items" ("id", "price", "Totalweight", "created_at", "updated_at", "url") VALUES (?, ?, ?, ?, ?, ?)>
    
[/code]

とエラーがでてしまいます。

Activerecordのupdateメソッドはidが同じという条件下に使用するものではないのでしょうか？  
IDがUniqueじゃない！ と言われてももちろんそうYO!と思ってしまうのですが、、  
どうやってidが同じものを更新すればよいのでしょうか？  
ググってもupdate, update_attributes, update_attributeしかでてきませんでした。

idがなければ、新しくインスタンスを作り、saveし、  
そのidのレコードがあれば、更新するというようにしたいのです。

追記  
エクセル, CSVのスプレッドシートを読み込むgemを使用しておりまして、  
def self.import(file)のメソッドの、spreadsheetを読み込んだ  
後、rowメソッドはgem rooによるものです。

gem "roo"  
<https://github.com/roo-rb/roo>

[code]

      COLUMN = ["id","tag_list","price","url","Perweight","Totalweight", "memo", "id", "created_at", "updated_at"]
    
      def self.import(file)
        spreadsheet = open_spreadsheet(file)
        header = spreadsheet.row(1)
        (2..spreadsheet.last_row).each do |i|
          row = Hash[[header, spreadsheet.row(i)].transpose]
          if Item.find(row["id"]) then
            product = Item.new
            attr = row.slice(*COLUMN)
            # product.attributes = attr
            #updateやupdate_attributesには引数をハッシュで渡すよう。
            product.update(attr)
          else
            product = Item.new
            attr = row.slice(*COLUMN)
            product.attributes = attr
            product.save!
          end
    
    
        end
      end
    
      def self.open_spreadsheet(file)
        case File.extname(file.original_filename)
        when ".csv" then
          Roo::Spreadsheet.open(file.path, extension: :csv)
        when ".xls" then
          Roo::Spreadsheet.open(file.path, extension: :xls)
        when ".xlsx" then
          Roo::Spreadsheet.open(file.path, extension: :xlsx)
        else raise "Unknown file type: #{file.original_filename}"
        end
      end
    
[/code]


CC BY-SA 3.0
2015-11-07T10:28:12.457
18513
2015-11-07T18:50:02.590
2015-11-07T11:03:33.507
5828
5828
question
ruby-on-rails ruby rails-activerecord
Activerecordの更新のメソッドを使っているのに、idがuniqueではないYOと出る。


何故かわかりました！  
同じidを持つItemオブジェクトを２つ作成しているのが原因です。  
更新する場合は、そのidのattributesを更新するように挿入する必要があり、  
idは同じオブジェクトであっても、さらにオブジェクトを入れることはできないようです。

ここからは憶測ですが、オブジェクトにid以外の固有の何か識別するものが与えられているものだからだと思われます。オブジェクトを生成した際に、１６進数のアレかなとおもってます↑

[code]

    product = Item.find(row["id"])
    if product then
      attr = row.slice(*COLUMN)
      # 更新する。
      product.update(attr)
    else
    ...
    end
    
[/code]

か

[code]

    # idが存在するか確かめ, なければ新しいidを作ってイニシャライズする。
    product = Item.find_or_initialize_by(id: row["id"])
    attr = row.slice(*COLUMN)
    product.attributes = attr
    product.save!
    
[/code]

ルールとしてやっていいのか分からなかったですが、英語のstackoverflowにても質問しました↑  
リンクは[update method of ActiveRecord failed because UNIQUE constraint failed:
items.id](https://stackoverflow.com/questions/33585569/update-method-of-
activerecord-failed-because-unique-constraint-failed-items-id)  
になります。  
上記の内容は、質問に回答頂いたNilsさんの回答をもとに意訳してあります。

というわけで、回答を締め切らせて頂きます。  
ありがとうございました！！！


CC BY-SA 3.0
2015-11-07T18:50:02.590
18528
2015-11-07T18:50:02.590
2017-05-23T12:38:56.083
-1
5828
18513
answer