What's the best approach to import multiple lines from a text_area in a form?
I've tried a quick bodge using FasterCSV but get a NoMethodError:
undefined method `pos' for {"name"=>"Carrots\r\nPeas\r\nRed Onion"}*
def create
FasterCSV.parse(params[:ingredient], {:headers => false, :quote_char => '"', :col_sep => ','}).each do |row_data|
new_record = Ingredient.new('name' => row_data[0])
new_record.save
end
I want to apply the final thing to a model with multiple columns hence the col_sep
If you want to use FasterCSV.parse on single lines, you need to get simple lines first.
Split the multi-line data first:
params[:ingredient][:name].split.each do |line|
FasterCSV.parse(line, { ... options ... }).each do |row_data|
... etc ...
I might use parse_line to explicitly communicate I'm working on a single line instead.
Related
So I set up a postgres server and have it working with hstore values.
As of right now, I have a table books, structured with
name:string data:hstore
I have created a sample entry to test:
Book.create(:name => "My First Book", :data => {'author' => 'Kevin', 'pages' => 368})
I have loaded the data into a variable:
#book = Book.where("data ? :key", :key => 'pages')
(just to test, i realize this query would serve no real purpose...)
I print the data as JSON and this works fine, the entry is found and displayed. However, what I am trying to do is access, say the pages, an hstore value. I did some research and found
#book.data['pages']
However, when i try to run this, I get
undefined method `data' for #<Book::ActiveRecord....
Any and all help is greatly appreciated!
The Active Record where will give you an array even if there is only 1 value.
You can do
#book = Book.where("data ? :key", :key => 'pages')[0]
to get that record
and then
#book.data
will work as desired.
If you might get multiple records and just using the first found is ok you could also use:
#book = Book.where("data ? :key", :key => 'pages').first
#book.data
or just
#book = Book.where("data ? :key", :key => 'pages').first.data
After fiddling around, i found that I simply needed to call:
#book[0].data
I've been reading Checking for nil in view in Ruby on Rails but I'm struggling to implement the marked solution.
I want to only load a graph in my View if a result set is not nil.
Controller:
#statistics = # ...my ActiveRecord query...
Helper:
def show_stats(statistics)
if statistics.pluck(:count)
image_tag(Gchart.line :size => '640x260',
:stacked => false,
:title => '',
:data => [statistics.pluck(:count)],
:legend => ['Stats'],
:bar_colors => ['3300CC', '3399FF'],
:axis_with_labels => ['y'])
end
end
View (HAML):
= show_stats(#statistics)
Currently when there are no statistics, I get an error. I want the View to not render the graph if there are no statistics. What am I doing wrong in the helper?
Error:
undefined method `-' for nil:NilClass
on the line where I call the helper.
if i understand correctly statistics.pluck(:count) will always return an array consisting of values of count attribute for each record found.
in ruby empty array evaluates to true, you might try to rewrite that if line like this:
if statistics.pluck(:count).any?
in fact it's good idea to cache that value and not fetch it from db again few lines below:
if (counts = statistics.pluck(:count)).any?
...
:data => [counts]
...
end
also i assume :data option wants array of values and not array of array of values so the final version would be:
if (counts = statistics.pluck(:count)).any?
...
:data => counts
...
end
P.S. if you still have an error - please share a full backtrace with us, knowing only "undefined method" doesn't tell much
Why not check for #statistics in your view like follows:
= show_stats(#statistics) if #statistics
Did you try this?
= show_stats(#statistics) unless #statistics.nil?
I'm manually building an SQL query where I'm using an Array in the params hash for an SQL IN statement, like: ("WHERE my_field IN('blue','green','red')"). So I need to take the contents of the array and output them into a string where each element is single quoted and comma separated (and with no ending comma).
So if the array was: my_array = ['blue','green','red']
I'd need a string that looked like: "'blue','green','red'"
I'm pretty new to Ruby/Rails but came up with something that worked:
if !params[:colors].nil?
#categories_array = params[:colors][:categories]
#categories_string =""
for x in #categories_array
#categories_string += "'" + x + "',"
end
#categories_string.chop! #remove the last comma
end
So, I'm good but curious as to what a proper and more consise way of doing this would look like?
Use map and join:
#categories_string = #categories_array.map {|element|
"'#{element}'"
}.join(',')
This functionality is built into ActiveRecord:
Model.where(:my_field => ['blue','green','red'])
Are you going to pass this string on to a ActiveRecord find method?
If so, ActiveRecord will handle this for you automatically:
categories_array = ['foo', 'bar', 'baz']
Model.find(:all, :conditions => ["category in (?)", categories_array])
# => SELECT * FROM models WHERE (category in ('foo', 'bar', 'baz'))
Hope this helps.
If you are using the parameter hash you don't have to do any thing special:
Model.all(:conditions => {:category => #categories_array})
# => SELECT * FROM models WHERE (category in ('foo', 'bar', 'baz'))
Rails (actually ActiveSupport, part of the Rails framework) offers a very nice Array#to_sentence method.
If you are using Rails or ActiveSupport, you can call
['dog', 'cat', 'bird', 'monkey'].to_sentence # "dog, cat, bird, and monkey"
Is there a way to parse feed's custom elements? Not feed entries', feed's custom elements. I know there is a way to do the same for the entries. Like,
Feedzirra::Feed.add_common_feed_entry_element("wfw:commentRss", :as => :comment_rss)
feed = Feedzirra::Feed.parse(some_atom_xml)
feed.entries.first.comment_rss # => wfw:commentRss is now parsed!
I want to be able to achieve the same for the feed object. Something like,
Feedzirra::Feed.add_common_feed_element("geo:lat", :as => :latitudes)
feed = Feedzirra::Feed.fetch_and_parse(“somerss”)
feed.latitudes # => 44.022448
Is there a way? Or does this requires writing a patch for FeedZirra?
It's a bit late, but more people might be looking for an answer.
Putting the following line in a file in your config/initializers seems to work:
Feedzirra::Parser::RSS.element :latitudes
According to the new http://feedjira.com/extending.html
# Add the generator attribute to all feed types
Feedjira::Feed.add_common_feed_element('generator')
Feedjira::Feed.fetch_and_parse("http://www.pauldix.net/atom.xml").generator # => 'TypePad'
# Add some GeoRss information
Feedjira::Feed.add_common_feed_entry_element('geo:lat', :as => :lat)
Feedjira::Feed.fetch_and_parse("http://www.earthpublisher.com/georss.php").entries.each do |e|
p "lat: #[e.lat}, long: #{e.long]"
end
Say I have model 'Car' and controller 'cars', and a method 'display'.
I have multiple attributes like:
in_production, year, make
I can easily do something like this to find cars that match all the parameters passed:
def display
#cars = Car.find(:all, :conditions => { :in_production => #{params[:in_production]}, :year => #{params[:year]}, :make => #{params[:make]} })`
end
So what I'm doing is coding hard links in the menu, so if I wanted to find all Nissan cars from 2009 that were in production, I would pass those values as parameters in my link.
On another page I want to show every car from 2009 that is in_production, only two params instead of three. What's the best way to dynamically alter the conditions so it will work with one, two, or three params, whilst using the same action?
Any ideas?
First of all, using
:conditions => "in_production = '#{params[:in_production]}' AND year = '#{params[:year]}' AND make = '#{params[:make]}'"
is vulnerable to SQL injection. You need to escape the user provided parameters before using them in database conditions.
Something like this should let you add conditions more dynamically depending on whether or not the parameters exist. I did not test it, so I may edit it shortly...
def display
conditions = []
conditions << [ "in_production = ?", params[:in_production] ] if params[:in_production].present?
conditions << [ "year = ?", params[:year] ] if params[:year].present?
conditions << [ "make = ?", params[:make] ] if params[:make].present?
#cars = Car.all(:conditions => conditions )
end
Certainly escape the params and ensure that you only query against fields you want to be exposed. Beyond that, you could use what is built into Rails:
Car.find_all_by_in_production_and_year_and_make(in_production, year, make)
Hand-rolling the conditions may allow for additional logic to be applied (search by year only if the year is between x and y, etc). Using the rails finders (which in turn use method_missing) keeps the API clean and flexible without having to stare at direct SQL conditions.
You could construct a Car#search method that takes the entire params hash as input, where the params are sanitized and stripped of non-exposed fields, and construct the Car#find_all_by* method call using the param names themselves. Adding new conditions to search by is then as simple as passing them in the params.
You might check out searchlogic. It uses some method missing magic to construct named_scopes that would do what you want.
http://github.com/binarylogic/searchlogic
I use SmartTuple for stuff like this. Simple, powerful, designed specifically for the task.
#cars = Car.all(:conditions => (SmartTuple.new(" AND ") +
({:in_production => params[:in_production]} if params[:in_production].present?) +
({:year => params[:year]} if params[:year].present?) +
({:make => params[:make]} if params[:make].present?)
).compile)
or
#cars = Car.all(:conditions => [SmartTuple.new(" AND "),
({:in_production => params[:in_production]} if params[:in_production].present?),
({:year => params[:year]} if params[:year].present?),
({:make => params[:make]} if params[:make].present?),
].sum.compile)
or
keys = [:in_production, :year, :make]
#cars = Car.all(:conditions => (SmartTuple.new(" AND ").add_each(keys) do |k|
{k => params[k]} if params[k].present?
end).compile)
Pick the one you like the most. :)