前提・実現したいこと
現在2つのモデルでメソッドを定義しています。ScrapingモデルとGearモデルです。
GearモデルおよびScrapingモデルそれぞれで、Gearのinitializeを行いたいのですが、タイトルのエラーが出てしまいます。
原因はおそらくinitializeであろうことはわかっているのですが、対処方法がわかりません。
ご教示頂けますと幸いです。
発生している問題、エラーメッセージ
スクレイピング後、seedsファイルを作成しました。
bundle exec rake db:seedを実行すると、表題のエラーが出ました。
この時、Gearモデルのinitializeメソッドをコメントアウトすれば問題なく動作します。
(スクレイピングのメソッドを実行するときも、initializeメソッドをコメントアウトしないと動作できませんでした)
models/gear.rbのコードです。
ruby
1 attr_accessor :points, :review_list, :n 2 has_many :likes, dependent: :destroy 3 has_many :reviews 4 5 validates :gearname, presence: true 6 7 8 def like_user(id) 9 likes.find_by(user_id: id) 10 end 11 12 def initialize(gear_id) 13 @n = 0 14 @points = 0 15 @review_list = Review.where(gear_id: gear_id) 16 end 17 18 # 任意のギアのレビューにおいて、引数で指定したカラムの平均点を計算 19 def self.average_point(gear_id, culumn) 20 gear = Gear.new(gear_id) 21 point_list = gear.review_list.pluck(:"#{culumn}") 22 point_list.each do |list| 23 gear.points += list 24 gear.n += 1 25 end 26 gear.points / gear.n.to_f 27 end 28end
models/scraping.rbのコードです。
ruby
1class Scraping 2 attr_accessor :links, :agent, :n 3 4 def initialize 5 # hrefのURLを格納する配列を用意 6 @links = [] 7 # 共通で使うのでMechanizeを変数化 8 @agent = Mechanize.new 9 # 初回のスクレイピングは、指定したURLであり、その後はリンク先に飛ばしたいので、処理回数nを定義する 10 @n = 0 11 end 12 13 # ブランドごとの機材一覧ページを指定すると、画像ファイルや詳細情報を取ってくる 14 def self.boss_urls 15 scraping = Scraping.new 16 current_page = scraping.agent.get('https://www.digimart.net/search?brandId=258&category12Id=&nosoldoutp=on') 17 page_links(current_page, scraping.n, scraping.links) 18 scraping.n += 1 19 end 20 21 # 一覧ページから詳細ページへのhref属性を抽出して、配列linksに順次格納していく 22 def self.page_links(current_page, n, links) 23 loop do 24 # 初回は指定したURLを読みにいく 25 if n == 0 26 elements = current_page.search('.itemSearchBoxLeft .pic a') 27 elements.each do |ele| 28 links << ele.get_attribute('href') 29 end 30 # 2回目以降は、ページネーションの'次へ'ボタンをクリックした先のURLを読み出しにいく 31 else 32 next_link = current_page.link_with(text: '次へ').click 33 break unless next_link 34 35 current_page = agent.get(next_link) 36 elements = current_page.search('.itemSearchBoxLeft .pic a') 37 elements.each do |ele| 38 links << ele.get_attribute('href') 39 end 40 end 41 # クラスメソッドlink_eachを実行 42 link_each(links) 43 end 44 end 45 46 # links配列に入れた詳細ページへのURLを一つ一つ抽出 47 def self.link_each(links) 48 links.each do |link| 49 # 過度なスプレイピングになるので、5秒ストップ 50 sleep(8) 51 # https://www.digimart.net~~~というURLにアクセスして、get_productの処理を行う 52 puts get_product('https://www.digimart.net' + link) 53 end 54 end 55 56 # link先から、機材名、メーカー、カテゴリー、画像URLを抽出してgearテーブルに保存する 57 def self.get_product(link) 58 agent = Mechanize.new 59 page = agent.get(link) 60 gearname = page.search(".itemDetailBox h1").inner_text if page.at('.itemDetailBox h1') 61 gearname = gearname.gsub(/(BOSS|MXR|Electro-Harmonix|tc electronic|BEHRINGER|Ibanez|LINE 6)|^(| )|【.+|(.+|《.+|即.+|☆.+|[.+/, '').lstrip.gsub("\u00A0", "") 62 maker = page.search(".itemDetail .itemDetailInfo a").inner_text if page.at('.itemDetail .itemDetailInfo a') 63 category = page.search('//*[@id="main"]/div/div[1]/ul/li[3]/a').inner_text if page.at('//*[@id="main"]/div/div[1]/ul/li[3]/a') 64 image_url = page.at('.mainPhotoBlock img')[:src] if page.at('.mainPhotoBlock img') 65 image = 'http:' + image_url 66 67 # メーカー名が存在しない場合は、その他というレコードで保存したいので条件分岐 68 maker = maker_check(maker) 69 # カテゴリ名が存在しない場合は、その他というレコードで保存したいので条件分岐 70 category = category_check(category) 71 scraping_save(gearname, image, maker, category) 72 end 73 74 # first_or_initializeを使って、gearnameとimageでは同じレコードを許さない。makerとcategoryは重複してもかまわない 75 def self.scraping_save(gearname, image, maker, category) 76 # binding.pry 77 gear = Gear.where(gearname: gearname, image: image).first_or_initialize 78 gear.maker = maker 79 gear.category = category 80 gear.save 81 end 82 83 def self.maker_check(maker) 84 maker = 'その他' if maker.nil? 85 maker 86 end 87 88 def self.category_check(category) 89 category = 'その他' if category.nil? 90 category 91 end 92end
試したこと
スクレイピング時に、下記場所にbinding.pryを入れてみました。
gear.rbのinitializeメソッドがあるとき ⇨ Gear.where(gearname: gearname, image: image).first_or_initializeでnot initialized
gear.rbのinitializeメソッドをコメントアウト ⇨ Gear.where(gearname: gearname, image: image).first_or_initializeはオブジェクト化成功
でした。
ruby
1 def self.scraping_save(gearname, image, maker, category) 2 # binding.pry 3 gear = Gear.where(gearname: gearname, image: image).first_or_initialize 4 gear.maker = maker 5 gear.category = category 6 gear.save 7 end
なにかヒントがありましたら、ご教示頂けますと助かります。
回答1件
あなたの回答
tips
プレビュー