Capturing Webpages Using Nokogiri -- Need to semi-persistent data - ruby-on-rails

I've got a module that does webscraping. I use this method a number of times, since it captures all the data on the webpage.
def page_as_xml(uri)
#page_as_xml ||= Nokogiri::HTML(open(uri))
end
Since I'll use the above method a handful of times for each page, it makes sense to keep it in an instance variable. However, how do I "empty out" the instance variable after I'm done?
All the webcsraping ends up in a hash (see below). If I don't "empty out" the instance variable, then the same page_as_xml data will get used for each page.
:page1 =>
{
:url => #page1,
:title => download_title(#page1),
:meta_tags => download_robots_tags(#page1)
},
:page2 =>
{
:url => #page2,
:title => download_title(#page2),
:meta_tags => download_robots_tags(#page2)
},
:page3 =>
{
:url => #page3,
:title => download_title(#page3),
:meta_tags => download_robots_tags(#page3)
},

How about make it a hash:
#pages_as_xml[uri] ||= Nokogiri::HTML(open(uri))
Now you don't have to worry about emptying it (unless memory is an issue).
I don't really understand why you need to call it more than once though. Also why do you call it page_as_xml if it is html?

Related

PayPal integration in Ruby on Rails

I want to add PayPal payment system to my RoR app. For this I did install paypal-sdk-rest gem.
I have a model Feed and inside of index.html.rb, where the route is:
get '/:locale/feed', to: 'feed#index', as: 'feed'
I want to paste the next code:
<%= link_to 'checkout', feed.paypal_url(products_url) %>
And inside of the model feed.rb:
def paypal_url(return_url)
values = {
:business => 'my_paypal_mail#gmail.com',
:cmd => '_cart',
:upload => 1,
:return => return_url,
}
values.merge!({
"amount_1" => unit_price,
"item_name_1" => name,
"item_number_1" => id,
"quantity_1" => '1'
})
"https://www.sandbox.paypal.com/cgi-bin/webscr?" + values.to_query
end
But it prints me, that:
undefined local variable or method `feed' for #<#<Class:0x007f5644b79520>:0x007f5644b89858>
on
<%= link_to 'checkout', feed.paypal_url(feeds_url) %>
What is the problem and how can I fix this error?
UPDATE
I just want to paste button just for payment, to my website with the amount 1$. How can I make it?
Where is feed object defined? If in controller then it should be instance variable like #feed, To access variables defined in controller from views we have to defined them as instance variables like #feed.

Rails: Setting class and data-tag of an HTML attribute with a single rails method

I'm currently working on a tour interface that guides new users around my site. I have a Tour model that has many TourStops, each of which contains information about a section of the site.
Basically, I'd like to write a function for the Tour model that -- when passed the number of a TourStop -- generates the correct class and data attribute for the HTML element it's attatched to. For example, I'd like
<%= link_to image_tag("new_button.png", tour.stop_data(1), :title => 'Add new asset'), new_asset_path %>
to call a function and return something like
def stop_data(order)
" :class => '#{tour_stops.find_by_order(order).name}',
:data => '{:order => order}'"
end
creating a link_to tag like:
<%= link_to image_tag("new_button.png", :class => 'tour_stop_1',
:data => {:order => 1}, :title => 'Add new asset'), new_asset_path %>
The above code doesn't work. Is something like this even possible? If not, what's a better approach I might take?
The image_tag accepts two parameters. A source, and a options Hash.
What you are trying to do is squeezing your return value from stop_data into this options Hash.
In order to get this to work, you first, need to return a Hash from stop_data, and second, make sure you pass only two arguments to image_tag - the source, and the options.
First:
def stop_data(order)
{
:class => tour_stops.find_by_order(order).name,
:data => { :order => order } # you may need order.to_json
}
end
Second:
link_to image_tag("new_button.png", tour.stop_data(1), :title => "Add new asset"), new_asset_path
This looks like it will work, but it won't, since your'e passing three parameters to image_tag.
When you do the following:
image_tag("new_button.png", :class => "tour_stop_1", :data => { :order => 1 }, :title => "Add new asset")
It looks like you're passing even 4 parameters to image_tag, but in fact they are only two. In Ruby, when the last parameter of a method is a Hash, you don't need to wrap the Hash key/value pairs in curly braces ({}), so the example above is essentially the same as
image_tag("new_button.png", { :class => "tour_stop_1", :data => { :order => 1 }, :title => "Add new asset" })
Now, to get your helper to work with image_tag, you need to merge the options, so they become only one Hash.
link_to image_tag("new_button.png", tour.stop_data(1).merge(:title => "Add new asset")), new_asset_path
Again, we're omitting the curly braces when calling merge, because it's only (and therefore last) parameter is a Hash. The outcome is the same as:
tour.stop_data(1).merge({ :title => "Add new asset" })

How to run some check based on the previous status of an instance before that it is stored in the database?

I am using Ruby on Rails 3.2.2 and I would like to run some check based on the previous status of an #article instance before that it is stored in the database. That is, I have to run some method that make use of data already stored in the database related to #article (in the below case that data is {:id => 1, :title => "Sample title", :content => "Sample content", :status => "private"} and not {:id => 1, :title => "Sample title changed!", :content => "Sample content", :status => "private"}).
I thought to proceed "retrieving"/"re-building" the original instance after that its attribute values have changed. That is:
# In the controller file
# #article.attributes
# => {:id => 1, :title => "Sample title", :content => "Sample content", :status => "private"}
#article.update_attributes(params[:article])
# => {:id => 1, :title => "Sample title changed!", :content => "Sample content", :status => "private"}
# In the model file
before_save :retrieve_original
def retrieve_original
# self.attributes
# => {:id => 1, :title => "Sample title changed!", :content => "Sample content", :status => "private"}
original = ... # ?
# original.id
# => nil
# original.attributes
# => {:title => "Sample title", :content => "Sample content", :status => "private"}
# self.attributes
# => {:id => 1, :title => "Sample title changed!", :content => "Sample content", :status => "private"}
end
So, original should be an Article object and just a duplicate of the #article instance (without the id and without that #article attributes have changed).
I tried to play with some Ruby on Rails method (like ActiveRecord::Base.dup or ActiveModel::Dirty.changed_attributes), but I have not found a solution. Furthermore, I think that there's a better way to accomplish what I would like to make compared to my approach. If so, what I might do?
I would like to do that because, for example, if an article is public it should be not possible to change the title value; if the article is private, it should be possible to change the title value. Of course, I have to make that check before to store the edited article data and for all attempts that try to update that data (for this I chose to use a before_save callback). However, if the user try to change the title value and the private value to public, then all checks run in a public "context", but I would like that those checks still run in a private "context" since the previous status was private.
It looks like you can go through the changes hash in your hook. I.e. dup or clone the changed version, then go through changed version's changes and set the attributes back to what they were for your copy.
just save
#article = Article.find(params[:id])`
#orginal = #article
if #article.update_attributes(params[:article])
#original.do_some_method_that_probably_should_be_a_before_update
#.... whatever is next .....
end
Or rethink why you need to do what you think you need to do.
There are a few ways you can do this. Basically, instead of trying to revert the changes afterwords and checking then, it would be easier to make a copy of the object before changes are made.
One way to do this is to create a new object from the 'attributes' of the current object like this:
tmp_article = #article.attributes
Do this before you make any changes to the model object. Then before you save you can use the hash .diff method that's built-in to rails:
diff_hash = tmp_article - #article.attributes
# diff will now contain any differences. It will be empty if they are identical.
Here's a link to the diff extension in Rails:
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/hash/diff.rb

Rails: confused about syntax for passing locals to partials

Understanding Rails "magic" with regards to rendering partials (and passing locals into them).
Why does this work:
<%= render "rabbits/form" %>
And this work:
<%= render "rabbits/form", :parent => #warren, :flash => flash %>
but this does not work:
<%= render "rabbits/form", :locals => { :parent => #warren, :flash => flash } %>
But this does:
<%= render :partial =>"rabbits/form", :locals => { :parent => #warren, :flash => flash } %>
Also, how can I look up these nuances so I don't need to bother people on S.O.?
The short answer is the render method looks at the first argument you pass in. If you pass in a hash (which includes :partial => 'foo', :locals => {blah blah blah}) then it will pass in all of your arguments as a hash and parse them accordingly.
If you pass in a string as your first argument, it assumes the first argument is your partial name, and will pass the remainder as your locals. However, in that subsequent call, it actually assigns :locals => your_locals_argument, which in this case is the entire :locals => {locals hash}, instead of just {locals hash}; i.e. you end up with :locals => {:locals => {locals hash}}, rather than :locals => {locals hash}.
So my advice is just to always explicitly pass values the same way all the time, and you won't have problems. In order to learn about this, I went directly to the code itself (actionpack/lib/base.rb, render() method in Rails 2; Rails 3 is different). It's a good exercise.
Furthermore, don't worry about "bothering" people on SO. That's why this site exists. I even learned something from this.
if you need to specify :locals, you need to specify :partial or :template
<%= render :partial => "rabbits/form", :locals => {...} %>
should work
To be honost, I only know about these use cases, because I have been keeping up with Rails for the last couple of years and read the announcements that a new way of doing it has been added. I often make a mistake in it myself, but usually it's easily corrected.
It's one of those parts of Rails API that hasn't been thoroughly thought through, if you ask me. It just accumulated more and more syntactic sugar over the years, without deprecating any of the old behavior. The render method has diabetes.
To make it even worse, render behaves differently in controller and view. I also looks at the first argument's content to see if it's a file, template, action or partial. If it starts with a slash then it's a file, or something like that.
I am in favor of using the shorter notation whenever possible. Because the short notations do communicate the intent quite well. When reading it, it usually does what you think it does. Writing partials is not straight forward.
Here is the source of render method from http://api.rubyonrails.org/classes/ActionView/Rendering.html#method-i-render:
def render(options = {}, locals = {}, &block)
case options
# Here is your last case
when Hash
if block_given?
_render_partial(options.merge(:partial => options.delete(:layout)), &block)
elsif options.key?(:partial)
_render_partial(options)
else
template = _determine_template(options)
lookup_context.freeze_formats(template.formats, true)
_render_template(template, options[:layout], options)
end
when :update
update_page(&block)
else
# here the first three cases
_render_partial(:partial => options, :locals => locals)
end
end
Hope this help!

Ruby on Rails / Yellow Maps For Ruby Plugin woes

Okay I've read through the plugin comments and the docs as well and I have yet to come up with an answer as to how to do this. Here's my problem I want to use the :info_window_tabs and the :icon option, but I don't know what format to pass my information in. According to the documentation the following code should be correct. Here's my code:
#mapper.overlay_init(GMarker.new([map.lat, map.lng],
:title => map.name,
:info_window_tabs => [
{:tab => "HTML", :content => #marker_html},
{:tab => "Attachments", :content => "stuff"}],
:icon => {
:image => "../images/icon.png"
}))
The readme and documentation can be viewed here.
And the relevant ruby file that I am trying to interact with, including the author's comments, can be viewed here.
I have tried the #rubyonrails channel in IRC as well as emailing the author directly and reporting an issue at GitHub. It really is just a question of syntax.
Thanks!
Okay, so I finally got this figured out. Here's how you do it; :icon accepts a GIcon variable and :info_window_tabs accepts an array of GInfoWindowTabs. Here is how you would declare each with the plugin.
Declare GIcon
#mapper.icon_global_init(GIcon.new(:image => "../images/civil.png",
:icon_anchor => GPoint.new(0,0),
:shadow => "../images/shadow.png",
:shadow_size => GSize.new(37,32),
:info_window_anchor => GPoint.new(9,2)), "civil_icon")
#civil_icon = Variable.new("civil_icon")
Declare GInfoWindowTab
#tab1 = GInfoWindowTab.new('Tab 1 Label', 'HTML for inside of tab1')
#tab2 = GInfoWindowTab.new('Tab 2 Label', 'HTML for inside of tab2')
#window_tabs = [#tab1, #tab2]
Then in your GMarker declaration just do the following:
#mapper.overlay_init(GMarker.new([map.lat, map.lng],
:title => map.name,
:icon => #civil_icon,
:max_width => 300,
:info_window_tabs => #window_tabs))
And you're done.

Resources