#1 Od: Tomas K., April 22nd, 2014 03:54
Dobrý den,
mám dotaz
načítám z xml
<?xml version="1.0" encoding="UTF-8" ?>
<SHOP>
<SHOPITEM>
<ITEM_ID>8159</ITEM_ID>
<PRODUCT></PRODUCT>
<DESCRIPTION></DESCRIPTION>
<URL>http://www.domovhracek.cz/</URL>
<IMGURL>http://www.domovhracek.cz/css/images/beznahledusmall.png</IMGURL>
<EAN></EAN>
<PRICE>2391</PRICE>
<CATEGORYTEXT>zaradit</CATEGORYTEXT>
<MANUFACTURER>Domov hraček</MANUFACTURER>
<PRICE_VAT>2893.00</PRICE_VAT>
<DELIVERY_DATE>0</DELIVERY_DATE>
</SHOPITEM>
</SHOP>
s tím, že pokud najdu v mé db existujicí ITEM_ID tak by se mělo udělat update . bohužel kod přidává jen nové položky
class ImportController < ApplicationController
def importer
require 'open-uri'
require 'nokogiri'
doc = Nokogiri::XML(open("http://www.domovhracek.cz/feed/heureka.xml"))
doc.css('SHOPITEM').each do |node|
children = node.children
@conditions={:ITEM_ID=> children.css('ITEM_ID').inner_text}
begin
record = ShopItem.find(:first, :conditions => {:ITEM_ID=>children.css('ITEM_ID').inner_text} )
record.PRODUCT=children.css('PRODUCT').inner_text
record.DESCRIPTION=children.css('DESCRIPTION').inner_text
record.save
rescue
record= ShopItem.create({:ITEM_ID=> children.css('ITEM_ID').inner_text})
record.PRODUCT=children.css('PRODUCT').inner_text
record.DESCRIPTION=children.css('DESCRIPTION').inner_text
record.save
end
end
end
#2 Od: Josef Šimánek, April 23rd, 2014 07:40
Ahoj. Můžeš nám sdělit, kterou používáš verzi Rails? Tohle vypadá jako 2.3, je to možné?
#3 Od: Tomas K., April 23rd, 2014 09:57
#4 Od: Josef Šimánek, April 23rd, 2014 16:28
Ahoj, tak můžeme po bodech.
- Není většinou nejlepší zachytávat obecnou vyjímku, ale jen tu, kterou očekáváš a chceš zachytit. Čili místo
rescue
by se tady hodilo něco jako rescue ActiveRecord::RecordNotFound
. To by ti tady ale také nepomohlo, viz následující bod.
-
ShopItem.find(:first, :conditions => {})
je staré ActiveRecord API, které už na Rails 4 a víc není podporováno. Podívej se na novější API na http://guides.rubyonrails.org/active_record_basics.html
- ActiveRecord umožňuje přes find_or_initialize oboje chování naráz. Čili zkusit najít podle parametrů a případně podle parametrů udělat novou instanci (neuloženou). Já preferuju řetězové použití syntaxe. Například pro tvůj případ to bude:
ShopItem.where(:item_id =>children.css('ITEM_ID').inner_text)
.first_or_initialize. Poté stačí přiřadit atributy podobně jak děláš ty.
- Když už se tady ptáš, tak ti doporučuju podívat se na metodu
Hash::from_xml
z active support. Nokogiri je tu jako kanón na vrabce. Místo procházení složité struktůry přes nokogiri můžeš zavolat Hash.from_xml(open("http://www.domovhracek.cz/feed/heureka.xml").read)
. Dostaneš hezký Hash, se kterým můžeš pracovat normálně. Bude to ale pomalejší. Více o této metodě na http://api.rubyonrails.org/classes/Hash.html#method-i-from_xml.
- Dále není dobré dělat tyto operace přímo v kontroleru. Ideální místo je třeba v lib/ si udělat třídu Importer a do ní schovat kód pro import. Ten jen v kontroleru zavolat a podle výsledku vrátit mininálně nějáký HTTP stav.
Kdyby jsi něco nechápal, tak se klidně ptej dál.
Ještě přikládám ukázkovej kód:
require 'open-uri'
feed = open("http://www.domovhracek.cz/feed/heureka.xml").read
hash = Hash.from_xml(feed)
hash["SHOP"]["SHOPITEM"].each do |item|
item_id = item.delete("ITEM_ID")
shop_item = ShopItem.where("ITEM_ID" => item_id).first_or_initialize
shop_item.assign_attributes(item)
shop_item.save
end
Dobrým zvykem je držet jména kolonek malými písmeny, takže by to chtělo ještě vzít vždy item a převést klíče přes downcase na malá písmena.
Rybařím za Žižkov.rb.
#5 Od: Tomas K., April 24th, 2014 04:14
dobrý den zkousim vaš kod ale na radku
hash["SHOP"]["SHOPITEM"].each do |item|
vyskočí
no implicit conversion of String into Integer
#6 Od: Josef Šimánek, April 24th, 2014 05:50
Aha. Vynechal jsem docela podstatnou část a to převod přes Hash::from_xml
. Upravím předchozí příspěvek.
Případně pošli celej výpis chyby.
#7 Od: Tomas K., April 30th, 2014 10:08
Nahlášený obsah je skrytý.
#8 Od: Josef Šimánek, May 3rd, 2014 13:14
Ahoj, pro další otázku by bylo dobrý založit nové téma a tam uvést zároveň chybu (jak ti odpověděl i někdo na SO).
Systém běží na Discourse, nejlepší zážitek je se zapnutým JavaScriptem