Been at this for a while. If i tell Category to just create, everything works fine. If I tell it to find_or_create I get errors.
已经有一段时间了。如果我告诉Category只是创建,一切正常。如果我告诉它find_or_create我会收到错误。
These work:
puts topic.at_xpath("@topicid")
puts topic.at_xpath("@topicname")
and
Category.create!(:topic_id => topic.at_xpath("@topicid"), :name => topic.at_xpath("@topicname"))
But these don't:
但这些不是:
Category.find_by_name(topic.at_xpath("@topicname"))
or
Category.find_or_create_by_topic_id_and_name(topic.at_xpath("@topicid"), topic.at_xpath("@topicname"))
Where am I messing up?
搞砸了哪里?
class FeedEntry < ActiveRecord::Base
require 'nokogiri'
require 'open-uri'
has_many :category_feeds
has_many :categories, :through => :category_feeds
accepts_nested_attributes_for :categories, :allow_destroy => true, :reject_if => proc { |obj| obj.blank? }
def self.nokogiri_get_feed
url = "http://some_feed.com/atom_feed"
doc = Nokogiri::HTML(open(url))
doc.remove_namespaces!
doc.search('feed entry').each do |item|
unless exists? :guid => item.css('id').text
create!(:name => item.css('title').text, :summary => item.css('title').text, :url => item.at_css("link")[:href], :published_at => item.css('updated').text, :guid => item.css('id').text)
item.xpath('content').each do |i|
i.css('topic').each do |topic|
id = topic.at_xpath("@topicid")
name = topic.at_xpath("@topicname")
update_attributes!(:categories=>[Category.find_or_create_by_topic_id_and_name(id, name)])
end
end
end
end
end
end
errors are:
ruby-1.9.2-p180 :001 > FeedEntry.nokogiri_get_feed
TypeError: Cannot visit Nokogiri::XML::Attr
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/visitor.rb:21:in `rescue in visit'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/visitor.rb:15:in `visit'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:260:in `visit_Arel_Nodes_Equality'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/visitor.rb:15:in `visit'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:120:in `visit_Arel_Nodes_Grouping'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/visitor.rb:15:in `visit'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:91:in `block in visit_Arel_Nodes_SelectCore'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:91:in `map'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:91:in `visit_Arel_Nodes_SelectCore'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:77:in `block in visit_Arel_Nodes_SelectStatement'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:77:in `map'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:77:in `visit_Arel_Nodes_SelectStatement'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/sqlite.rb:7:in `visit_Arel_Nodes_SelectStatement'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/visitor.rb:15:in `visit'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/visitor.rb:5:in `accept'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/arel-2.0.9/lib/arel/visitors/to_sql.rb:19:in `block in accept' ... 11 levels...
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/nokogiri-1.4.4/lib/nokogiri/xml/node_set.rb:238:in `each'
from /Users/pca/projects/cdapp/cdrails/app/models/feed_entry.rb:35:in `block (2 levels) in nokogiri_get_feed'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/nokogiri-1.4.4/lib/nokogiri/xml/node_set.rb:239:in `block in each'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/nokogiri-1.4.4/lib/nokogiri/xml/node_set.rb:238:in `upto'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/nokogiri-1.4.4/lib/nokogiri/xml/node_set.rb:238:in `each'
from /Users/pca/projects/cdapp/cdrails/app/models/feed_entry.rb:33:in `block in nokogiri_get_feed'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/nokogiri-1.4.4/lib/nokogiri/xml/node_set.rb:239:in `block in each'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/nokogiri-1.4.4/lib/nokogiri/xml/node_set.rb:238:in `upto'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/nokogiri-1.4.4/lib/nokogiri/xml/node_set.rb:238:in `each'
from /Users/pca/projects/cdapp/cdrails/app/models/feed_entry.rb:30:in `nokogiri_get_feed'
from (irb):1
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.3/lib/rails/commands/console.rb:44:in `start'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.3/lib/rails/commands/console.rb:8:in `start'
from /Users/pca/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.3/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
1 个解决方案
#1
3
Summary
Instead of these lines:
而不是这些线:
id = topic.at_xpath("@topicid")
name = topic.at_xpath("@topicname")
Use these instead:
请改用:
id = topic['topicid']
name = topic['topicname']
Explanation
Let's look at a simple test case:
让我们看一个简单的测试用例:
require 'nokogiri'
xml = Nokogiri::XML("<root foo='bar' />")
foo = xml.root.at_xpath('@foo')
puts foo
#=> bar
p foo
#=> #<Nokogiri::XML::Attr:0x15c1d64 name="foo" value="bar">
p foo.text
#=> "bar"
p xml.root['foo']
#=> "bar"
As you can see from the above, selecting an attribute via XPath actually gives you an Attr
node, which is not the same as the string value of that attribute. (Using puts
causes the to_s
method of the Attr to show you only the value, but that doesn't mean that it's actually a string.)
从上面可以看出,通过XPath选择属性实际上会为您提供一个Attr节点,该节点与该属性的字符串值不同。 (使用puts会导致Attr的to_s方法仅显示值,但这并不意味着它实际上是一个字符串。)
As shown above, you need to use the text
method (or value
or content
) on the Attr nodes to get the string value back that you really wanted:
如上所示,您需要使用Attr节点上的文本方法(或值或内容)来获取您真正想要的字符串值:
id = topic.at_xpath("@topicid").text
name = topic.at_xpath("@topicname").text
Alternatively (and more simply) use the Element#[]
method to fetch the value of an attribute off of an element directly:
或者(更简单地)使用Element#[]方法直接从元素中获取属性的值:
id = topic['topicid']
name = topic['topicname']
#1
3
Summary
Instead of these lines:
而不是这些线:
id = topic.at_xpath("@topicid")
name = topic.at_xpath("@topicname")
Use these instead:
请改用:
id = topic['topicid']
name = topic['topicname']
Explanation
Let's look at a simple test case:
让我们看一个简单的测试用例:
require 'nokogiri'
xml = Nokogiri::XML("<root foo='bar' />")
foo = xml.root.at_xpath('@foo')
puts foo
#=> bar
p foo
#=> #<Nokogiri::XML::Attr:0x15c1d64 name="foo" value="bar">
p foo.text
#=> "bar"
p xml.root['foo']
#=> "bar"
As you can see from the above, selecting an attribute via XPath actually gives you an Attr
node, which is not the same as the string value of that attribute. (Using puts
causes the to_s
method of the Attr to show you only the value, but that doesn't mean that it's actually a string.)
从上面可以看出,通过XPath选择属性实际上会为您提供一个Attr节点,该节点与该属性的字符串值不同。 (使用puts会导致Attr的to_s方法仅显示值,但这并不意味着它实际上是一个字符串。)
As shown above, you need to use the text
method (or value
or content
) on the Attr nodes to get the string value back that you really wanted:
如上所示,您需要使用Attr节点上的文本方法(或值或内容)来获取您真正想要的字符串值:
id = topic.at_xpath("@topicid").text
name = topic.at_xpath("@topicname").text
Alternatively (and more simply) use the Element#[]
method to fetch the value of an attribute off of an element directly:
或者(更简单地)使用Element#[]方法直接从元素中获取属性的值:
id = topic['topicid']
name = topic['topicname']