Rails: changing repetition into loops - ruby-on-rails-3

I'm trying to reduce repetition in my code. I have in several places this code (or variants thereof):
#articles1 = Article.all_articles(1).reverse
#articles2 = Article.all_articles(2).reverse
#articles3 = Article.all_articles(3).reverse
Is a way to change it to something like:
3.times do |i|
#articles[i+1] = Article.all_articles(i+1).reverse
end
Cheers!

How about:
#articles = (1..3).to_a.map { |i| Article.all_articles(i).reverse }

Related

What's the best way to sanitize destroy_all - Rails

I have the following controller in Rails:
class FooController < ApplicationController
def delete_foo(bar):
Foo.destroy_all("foo = '#{#bar}'")
Is
Foo.destroy_all("foo = ?", #bar)
always valid?
destroy_all works on a relation. Why not do
Foo.where(foo: bar).destroy_all
Foo.destroy_all("foo = ?", #bar), This is invalid.
From apidoc, we will find:
destroy_all(conditions = nil) public
destroy_all method only accepts a single argument, the argument can be a string, array, or hash. You cannot pass two arguments.
So you can write like this:
Foo.destroy_all("foo = #{#bar}")
Foo.destroy_all(foo: #bar)
Foo.where(foo: #bar).destroy_all

How to search across fields for a range of optional values using ActiveRecord in Ruby?

I'm coding up a search query where the user can search for Items by creator, title, or description, or any combination of the above.
So in my search controller logic I grab the params thusly:
creator = params['creator']
title = params['title']
description = params['description']
# todo: do some input validation here
results = nil
cr = User.roughly_named(creator).first
What I am doing now is:
q = []
q << "creator_id IS #{cr.id}" if cr
q << "title LIKE '%#{title}%'" if title != ''
q << "description LIKE '%#{description}%'" if title != ''
results = Item.where(q.join(' AND ')
but surely there is a better way. I am open to suggestions.
How about using scopes :
res = Item.scoped
res = res.where(["creator_id is ?", cr.id]) if cr
res = res.where(["title like ?", "%#{title}%"]) unless title.empty?
res = res.where(["description like ?", "%#{description}%"]) unless description.empty?
When doing Item.scoped, you basically do lazy loading. Iterating over res will actually execute the query. This is handy when chaining optional where clauses.
PS: prefer the ? syntax to prevent SQL injections.
You could simply achieve this with regular where clause
Or try dynamic finders? If that does not help either, you could use method_missing to create dynamic method call. It's explained elsewhere

multiple string queries on a single table

making a site for game trailers and on the front page I organize the games in terms of their category, so I end up doing this (rails):
def index
#newGames = Game.order("created_at DESC").limit(3)
#casualGames = Game.where("category = 'casual'").limit(9)
#actionGames = Game.where("category = 'action'").limit(8)
#strategyGames = Game.where("category = 'strategy'").limit(9)
#adventureGames = Game.where("category = 'adventure'").limit(8)
#puzzleGames = Game.where("category = 'puzzle'").limit(9)
end
Is there a way to accomplish the same thing but without making 6 separate queries on the sable table?
Thanks
As your search parameters are different querying DB multiple times is unavoidable. However you can make your controller skinny. Create a class method in Game class and collect and return everything you need in a hash.
Game.rb
def self.for_index_page
games = {}
games.merge!(new: order("created_at DESC").limit(3))
games.merge!(casual: category_with_limit('casual', 9)
games.merge!(action: category_with_limit('action', 8)
...
end
def self.category_with_limit(category, limit)
where(category: category).limit(limit)
end
GamesController.rb
def index
#games = Game.for_index_page
end
index.erb
<%=#games[:new] %>
<%=#games[:casual] %>
...

Eager Loading by Setting Variable

Sorry in advance for this incredibly simple question, but what is the best way to set a variable while also checking a condition. For example, I have:
#friends = []
#user.facebook_friends.each do |key,value|
if test = Authorization.includes(:user).find_by_uid(key) != nil
#friends << {"name" => test.user.name, "facebook_image_url" => test.user.facebook_image_url}
end
end
I am trying to pull in the user records when I pull in the authorization record, so as to minimize my database queries. I know that I can't write
test = Authorization.includes(:user).find_by_uid(key) != nil
in order to set the test variable. What is the best way to write this code so that it is functional?
You just need parens:
(test = Authorization.includes(:user).find_by_uid(key)) != nil
Also here is a more rails way to do it:
unless (test = Authorization.includes(:user).find_by_uid(key)).nil?
#friends << {"name" => test.user.name, "facebook_image_url" => test.user.facebook_image_url}
end

ROR Observer doesnt work

OrderItem observer doenst calculate total sum when updating OrderItem :((
what's wrong?
class OrderItemObserver < ActiveRecord::Observer
def after_save(order_item)
order_item.order.total_sum = order_item.order.order_items.collect{|i| i.price.to_i}.sum
end
end
listed in application.rb
config.active_record.observers = :order_observer, :order_item_observer
The result is being calculated then discarded as you are not saving the result.
class OrderItemObserver < ActiveRecord::Observer
def after_save(order_item)
order = order_item.order
order.total_sum = order.order_items.collect{ |i| i.price.to_i }.sum
order_item.save
end
end
Value is now saved. The order variable is just to tidy things up a little.