setting and array of params in rails - ruby

A series of objects need to be purchased in a single transaction, however each item must be a different transaction object due to relationship issues.
A confirmation action aims to list each of these items independently. The controller attempts to prepare parameters for viewing each transaction
<% #transactions.each do |transaction| %>
<%= params[:product_id][:product_id] %>
[...]
as follows:
#transactions = params[:product_ids].map do |product_id|
#transaction = Transaction.new
#inventories = Inventory.where(['product_id = ?', product_id]).all
#my_price = my_price
params[:product_id][:product_id] = product_id # sanity check
params[:product_id][:additional_info] = session[:additional_info]
params[:product_id][:rate] = #inventories.map(&#my_price).inject(0, :+)
end
#sub_total = #transactions.params[:product_id][:rate].sum
However undefined method []= for nil:NilClass is generated when building the params for each product_id. This command is obviously mistaken. [The approach could also be inefficient/ineffective...]

I believe you don't really mean params[:product_id][:product_id], but rather params[product_id][:product_id], since :product_id is a symbol, not a variable.
When setting a new hash in the hash, you need to first define it as such:
params[product_id] = {}
params[product_id][:product_id] = product_id
# ...
This should resolve the undefined method []= for nil:NilClass. I guess you will encounter some more problems (like #inventories.map(&#my_price)) after you fix this one though...
With some guesswork, I guess a code which does what you want will look something like this:
#transactions = params[:product_ids].map do |product_id|
transaction = Transaction.new
transaction.product_id = product_id # sanity check
transaction.additional_info = session[:additional_info]
transaction.rate = Inventory.where(['product_id = ?', product_id]).sum(:my_price)
transaction
end
#sub_total = #transactions.map(&:rate).sum
And the view would be something like this:
<% #transactions.each do |transaction| %>
<%= transaction.product_id %>
[...]

Related

undefined method with googlebooks

I'm building a library in sinatra, using postresql as database and a 'googlebooks' gem to find the informations I want.
This is my code in main.rb
get '/list' do
#books = GoogleBooks.search(params[:title])
erb :list
end
get '/info/:isbn' do
#this is to get the info from my database if there is any
if book = Book.find_by(isbn: params[:isbn])
#book_title = book.title
#book_authors = book.author
#book_year = book.year
#book_page_count = book.page_count
#book_id = book.id
#book_isbn = book.isbn
else
#use the gem to look for the data
text = GoogleBooks.search(params[:isbn])
#book_title = text.title
#book_author = text.authors
#book_year = text.published_date
#book_cover = text.image_link(:zoom => 2)
#book_page_count = text.page_count
#book_notes = text.description
#and then store it into the database
book = Book.new
book.title = #book_title
book.authors = #book_authors
book.publish_date = #book_year
book.image_link = #book_cover
book.page_count = #book_page_count
book.description = #book_notes
book.isbn = params[:isbn]
book.save
#book_id = book.id
end
erb :info
end
This is my erb file :list
<div class='list_by_title'>
<% #books.each do |text| %>
<ul>
<li class='list_by_title'>
<%= text.title %> (Authour: <%= text.authors %>)
</li>
</ul>
<%end%>
</div>
The list part works.. I'm able to have a page with a list of titles... the problem is when I try to call the data from the params isbn, I always have this error:
NoMethodError at /info/0596554877
undefined method `title' for #<GoogleBooks::Response:0x007ff07a430e28>
Any idea for a possible solution?
As per documentation, GoogleBooks::Response is an enumerator. So you need to iterate over it by using each, and invoke the title method on individual objects retrieved from enumerator.
result = GoogleBooks.search(params[:isbn])
result.each do |text|
#book_title = text.title
...
end
Variable name text for details about a book is not a good name, you need to pick apt variable names, many a times good variable names makes debugging easier

Iterate over a singleton or multiple of a returned DataMapper class

I have the following code
if admin_authorized?
#allschools = School.all
elsif faculty_authorized?
#allschools = School.get(Faculty.get(session[:faculty_id]))
end
I am getting this error
undefined method `each' for #<School:0x007f88a1360318>
#allschools will either be an array of schools or a singleton school. I need to iterate over this list in the view, like so:
<% #allschools.each do |s| %>
<%= f_optionselected(s.id.to_s, params[:school], s.name) %>
<% end %>
I've tried to do if statements with #allschools.count, #allschools.typeof(Array), ....
Should I use two different variables and a PHP type isset() statment to determine which block to display? Or is there a way to iterate over the statement in some Ruby way?
School.all returns an ActiveRecord::Relation and you can iterate through it, as you do with each. I think School.get returns a single School instance, right? Try to wrap it into an Array:
#allschools = [School.get(Faculty.get(session[:faculty_id]))]

ruby (for rails) sort_by instantiated variable

In a rails 3.2.17 application, with ruby 1.9.3, a method filters a previously-found set of products based on a condition. If it passes the condition, it creates an instance variable for the record (rate), which itself is the product of another method (shown_price).
#products = #inventories.map(&:product).uniq
def validarray
validarray = Array.new
#products.each do |product|
#inventories_for_product = #inventories.select{ |i| i.product_id == product.id }
if #inventories_for_product.count == #threshhold
product.rate = #inventories_for_product.map(&#shown_price).inject(0, :+)
validarray << product
end
end
validarray.sort_by{|p| p[:rate]}
end
#validarray = validarray
All elements in this method generate proper data which can be viewed via the browser. In fact (even re-calling sort_by)
<% #validarray.sort_by{|p| p[:rate]}.each do |vp| %>
<%= vp.id %> <%= vp.rate %><br />
<% end %>
will show the proper data.
Issue when I ask for descending order
#validarray.sort_by{|p| -p[:rate]}
undefined method `-#' for nil:NilClass
whereas for ascending order
no complaints, but no sorting either.
I assume that the symbol
:rate is wrong
and ruby lets the stuff unsorted as ASC is invoked by default and has nothing to sort with, but complains otherwise because it has no tools in its hands.
Most likely yourate attribute is not a column in products table, but it is defined as a method within Product model. This means that [] method on the model will always return nil, as it only reads given database column and perform a typecast. In short, do:
#validarray.sort_by &:rate
or (in reverse order)
#validarray.sort_by{|p| -p.rate }
Possibly not all products have a :rate value. You could either:
#validarray.sort_by{|p| p[:rate]}.reverse
or:
#validarray.sort_by{|p| -(p[:rate] || 0) }

Array of Ruby objects returning strings on each method. Why?

Useful additional info: I am using the decent_exposure gem so this might be the issue - correcting the code below:
expose(:get_filter_tags) do
if params[:filter_tag_names]
filter_tag_names = Array(params[:filter_tag_names].split(" "))
filter_tags = Array.new
filter_tag_names.each do |f|
t = Tag.find_by_name(f)
filter_tags << t
end
end
end
So, something funny happens when I call this in the view:
query string ?utf8=✓&filter_tag_names=test
<% get_filter_tags.each do |ft| %>
<%= ft.name %>
<% end %>
Error message: undefined method `name' for "test":String
Why is this trying to call name on a string not a Tag object? If I put the following in the view, and have jut one filter_tag_names item
def getfiltertag
Tag.find_by_name(params[:filter_tag_names])
end
#view
<%= getfiltertag.name %>
query string: ?utf8=✓&filter=test
like above then I can call name just fine, so obviously I am doing something wrong to get an array of strings instead of objects. I just don't know what. Any suggestions?
Your problem is that each returns self — so if you write filter_tag_names.each, it returns filter_tag_names. You could fix this by explicitly returning filter_tags, but more idiomatically, you could just rewrite it as:
expose(:get_filter_tags) do
if params[:filter_tag_names]
filter_tag_names = Array(params[:filter_tag_names].split(" "))
filter_tag_names.map {|f| Tag.find_by_name(f) }
end
end
Just as an aside, this method will return nil if there aren't any filter tag names. You may want to do that, or you might want to return an empty collection to avoid exceptions in the calling code.

Convert string to variable name in ruby

I have variables
<% mon_has_two_sets_of_working_hours = 0 %>
<% tue_has_two_sets_of_working_hours = 0 %>
<% wed_has_two_sets_of_working_hours = 0 %>
I want to change the values of these variables dynamically.
<% days_array = ['mon', 'tue', 'wed'] %>
<% days_array.each do |day| %>
<% if condition? %>
# here i want to set %>
<% "#{day}__has_two_sets_of_working_hours" = 1 %>
end
end
The value is not getting assigned. Is there any way to assign value to variable dynamically?
I don't think there is a way to do this. There is with instance or class variables, but with local variables there is very rarely a good need.
In your case you really should have the data in a hash. Also, logic like this really does not belong in erb. You want something like:
working_hour_sets = %w[mon tue wed thu fri sat sun].inject({}) do |hash, day|
hash[day]=0;
hash
end
# puts working_hour_sets #=> {"wed"=>0, "sun"=>0, "thu"=>0, "mon"=>0, "tue"=>0, "sat"=>0, "fri"=>0}
working_hour_sets.each do |day, value|
working_hour_sets[day] = 1 if condition?
end
Now, I know this question is a bit old, but there is an easier way to do this and is using the standard Ruby send method. This is actually one of the methods that make Ruby so agile in the metaprogramming world.
This is actually a config setting I use in a Rails app:
# In a YAML
twitter:
consumer_key: 'CONSUMER-KEY'
consumer_secret: 'CONSUMER-SECRET'
oauth_token: 'OAUTH-KEY'
oauth_token_secret: 'OAUTH-SECRET'
...
# And in your file.rb
config = YAML.load_file(Rails.root.join("config", "social_keys.yml"))[Rails.env]['twitter']
Twitter.configure do |twitter|
config.each_key do |k|
twitter.send("#{k}=", config[k])
end
end
It's DRY and very easy to understand. :)
Yet another answer to this old question.
In my scenario, I wanted to count how many times a day showed up in an array of days (day_array). I didn't need to know if a day didn't show up in day_array, so I didn't initialize the days_count hash as gunn did in his answer.
Here's how I did it:
def count_days(day_array)
days_count = {}
day_array.each do |day|
days_count[day].nil? ? days_count[day] = 1 : days_count[day] = days_count[day] + 1
end
puts days_count
end
If I copy and paste the above in irb, then:
> count_days(%w[SU MO])
{"SU"=>1, "MO"=>1}
> count_days(%w[SU SU MO])
{"SU"=>2, "MO"=>1}
Basically, consistent with prior answers. But, I thought an additional example couldn't hurt.

Resources