ROR Observer doesnt work - ruby-on-rails-3

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.

Related

How to pass ActiveRecord model class to Resque

Let's say I have the following Resque job:
class Archive
#queue = :file_serve
def self.perform(repo_id, branch = 'master')
repo = Repository.find(repo_id)
repo.create_archive(branch)
end
end
What if I wanted to make this more generic by passing an object id and the object's class so that I can do something like this:
class Archive
#queue = :file_serve
def self.perform(object_class, object_id, branch = 'master')
object = object_class.find(object_id)
object.create_archive(branch)
end
end
This doesn't work, obviously, and I don't have a sense for what I should be doing, so if anyone can give some guidance, that would be really appreciated!
I would pass the name of the class to the job, rather than the class itself. Then you could call constantize on the name to get the class back, and call find on it. eg.
def self.perform(class_name, object_id, branch = 'master')
object = class_name.constantize.find(object_id)
object.create_archive(branch)
end

Ruby on rails if condition when adding new data to a sql table

I'm pretty new to ruby & ruby on rails and I have a little question :
I want to set a boolean to true if the value of the entry is higher than X and another boolean to true if this value if lower than Y.
I don't really know where to do the code for this or what's the best way to do it.
To be clear, I have a form(made with a scaffold) where I ask a value and depending on this value one of the 2 boolean might be set to true.
Thanks for your help!
you can put this on your controller. I would assume that the form is on controller#create where you would have:
boolean = true if #model.value > x
boolean2 = true if #model.value < y
then save it on db with #model.save
Assuming those booleans are attributes of the same model you have value on, it seems you could do this in before_save callback:
class SomeModel < ActiveRecord::Base
# Your X & Y with some example values
X_VALUE = 5
Y_VALUE = 10
before_save do
self.boolean1 = self.value > X_VALUE
self.boolean2 = self.value < Y_VALUE
true # callback needs to return true, otherwise save will fail
end
end
With above implementation even if you update the value, the proper boolean values will change as well. I hope this helps, as it's made on some assumptions. If not let me know, we'll figure something out.

Rails: changing repetition into loops

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 }

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] %>
...

Increment integer on save in Rails 3?

I have the following code in my Rails 3 application:
def like
#suggestion = Suggestion.find(params[:id])
Suggestion.update_all("votes = (votes + 1)")
redirect_to suggestions_url
end
def dislike
#suggestion = Suggestion.find(params[:id])
Suggestion.update_all("votes = (votes - 1)")
redirect_to suggestions_url
end
It's working, but rather than updating the current suggestion it's updating them all. So I changed it to:
def like
#suggestion = Suggestion.find(params[:id])
#suggestion.update_all("votes = (votes + 1)")
redirect_to suggestions_url
end
def dislike
#suggestion = Suggestion.find(params[:id])
#suggestion.update_all("votes = (votes - 1)")
redirect_to suggestions_url
end
but then I get:
undefined method `update_all' for #<Suggestion:0x007f87c2b918a0>
So then I tried #suggestion.update_attribute(:votes, '1') but that resets the value to 1 instead of incrementing it.
What's the correct way to achieve this? I just want the integer (votes) of the current suggestion to increment/decrease by 1 on each save.
I've also tried the following with no luck:
def like
#suggestion = Suggestion.find(params[:id])
#suggestion.increment(:votes)
redirect_to suggestions_url
end
This seems more suitable in the model. I suggest creating a like method inside the model like so:
def like
self.increment!(:votes)
end
Now you can do something like this:
#suggestion = Suggestion.find(params[:id])
#suggestion.like
Note: increment!, with the exclamation point also performs the save action
A couple things. It sounds like what you want is a controller action that increments an attribute by one. You were probably closest with the code
#suggestion.update_attribute(:votes, '1')
If you check the documentation for that method, it sets the value of the attribute votes to the second arguement, the string '1', on the object, #suggestion, and its corresponding row in the database. Instead of setting it to '1', you want to set it to the incremented value:
#suggestion.update_attribute(:votes, #suggestion.votes + 1)
Ethan suggested using the convenience method, increment!, which works just the same.
Now, if you wanted to actually auto-increment each time the object gets saved (as in something else about the object gets altered, you'd want to use the :before_save callback with increment without the bang.