質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

1回答

1511閲覧

railsでcsvをインポートしたデータの処理方法について

EVAEVE

総合スコア3

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2020/09/01 09:30

csvファイルをインポートする処理を以下のように記述しました。
model/user.rb の次のコードで、Userモデルから条件に一致したレコード、一致していない場合には新たに作成してくれてます。

user = find_by('note = ? AND text = ? AND number = ?', row["note"], row["text"], row["number"]) || new

これと同じ挙動をuser.controller.rbで行いたい場合にはイイ案はあるでしょうか?
*例えば、上記のuserで、一致したものをupdate_userとして返し、一致しないものはnew_userとするなど

上記の後に、user.saveを行うと一致したものはupdate、一致しないものはcreateしてくれるのでとても便利なのですが、その前後で新たに処理を行いたいためです。
またモデル内で処理する場合、csvから取り込んだレコードの各カラム(row["name"]など)にカスタムでvalidateメソッドを作成することは可能でしょうか?

もし、よろしければ教えていただきたいです。

controller

1def import 2User.import(params[:file]) 3redirect_to users_url 4end

model

1class User < ApplicationRecord 2 def self.import(file) 3 CSV.foreach(file.path, headers: true, encoding: 'Shift_JIS:UTF-8') do |row| 4 user = find_by('note = ? AND text = ? AND number = ?', row["note"], row["text"], row["number"]) || new 5 user.attributes = row.to_hash.slice(*updatable_attributes) 6 user.save 7 end 8 end 9 10 def self.updatable_attributes 11 ["id","name","age","text","note","number"] 12 end 13 14end

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

同じ動作を行うものに、find_or_initialize_by(attributes, &block) というのがあります。attributesに一致したものがなければその値で作ってくれます。

「その前後で新たに処理を行いたい」というのはなにでしょうか。
既存のものと新規のもので使い分ける必要がある処理ですか?

validate はごく自然に、row["name"] なら :name に対してvalidationを書けば良いだけだと思うのですが、それではまずいことがある?

こんな使い方です

def self.import(file) CSV.foreach(file.path, headers: true, encoding: 'Shift_JIS:UTF-8') do |row| user = find_or_initialized_by(note: row["note"], text: row["text"], number: row["number"]) user.attributes = row.to_hash.slice(*updatable_attributes) user.save end end

投稿2020/09/01 11:33

編集2020/09/02 12:10
winterboum

総合スコア23347

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

EVAEVE

2020/09/01 12:27

winterboumさん ありがとうございます。 > find_or_initialize_by(attributes, &block) whereメソッドのように使えるんですね。具体的にどのように使用するんですか? > 「その前後で新たに処理を行いたい」というのはなにでしょうか。 csvからインポートした各レコードに対し、validateをかけるのと、他のモデルの値をuserのカラムに代入したいと思ってます。 > 既存のものと新規のもので使い分ける必要がある処理ですか? そうです。ほとんど一緒なんですが、SQL文を作るのに、"INSERT"と"UPDATE"に分ける必要があるので、使い分けようと思っています????なのでそれぞれを別は変数に格納できないかな?と思ってます。
winterboum

2020/09/01 12:32 編集

「具体的にどのように使用するんですか?」 質問にある最初の式のように。 マニュアルとか探してください。 「csvからインポートした各レコードに対し、validateをかけるのと、他のモデルの値をuserのカラムに代入したいと思ってます。」 は今やってるように、得られたuserに対して行えば良いのです 「そうです。ほとんど一緒なんですが、SQL文を作るのに、"INSERT"と"UPDATE"」 を意識する必要はなく、 save が判断してくれて使いわけてくれます。
EVAEVE

2020/09/02 09:47

def import CSV.foreach(params[:file], headers: true, encoding: 'Shift_JIS:UTF-8') do |row| values = row.to_h User.find_or_initialize_by(values) update_users = User.where('note = ? AND text = ? AND number = ?', values["note"], values["text"], values["number"]) || new_users = User.new(id: values["id"], name: values["name"],age: values["age"],note: values["note"],text: values["text"],number: values["number"]) end redirect_to users_url #end update_usersやnew_usersには入らなかったですね。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問