Ruby on Rails: setting future "publishing" dates for blog postings - ruby-on-rails

I'm trying to set blog postings to publish at certain dates in the future. I have in my Posting model:
named_scope :published, :conditions => ["publish_at <= ?", Time.now]
I'm using this in my controller to call the published postings:
#postings = Posting.published
The development server works fine, but I believe the production server needs me to refresh the cache (using "pkill -9 dispatch.fcgi") or I won't see the new postings when it's supposed to publish.
Is there any way to set future times for the postings' publishing dates correctly on the production server? Do I have to refresh the cache every time?

You are correct, because the named scope is evaluated when the class loads.
You should re-write it to be dynamic or (maybe better) use the database's now() function.
Either of these should work:
named_scope :published, lambda { {:conditions => ["publish_at <= ?", Time.now]} }
Note how this uses a lambda to always return the current time in the conditions hash.
named_scope :published, :conditions => "publish_at <= now()"
This is database dependent (the above should work for MySQL) but probably a tiny bit faster.

Check to see if you have any of the following statements in your production environment:
ActionController::Base.cache_store = :memory_store
OR
ActionController::Base.cache_store = :file_store, "/path/to/cache/directory"
OR
ActionController::Base.cache_store = :mem_cache_store
OR any other setting for ActionController::Base.cache_store

Related

How can I compose/chain queries in Rails 2?

I have one query that gets the total count of rows with one condition, and a second query that gets the total count of rows with the same condition plus another condition. Ideally, I wouldn't repeat myself in the code and could instead just chain/compose the extra condition onto the first query.
I'm thinking of something like this.
query1 = Table.find(:all, :conditions => "condition1")
query2 = query1.find(:all, :conditions => "condition2")
It'd also be nice to find out what this looks like for the Table.count use case, since that's what I'm actually trying to do at the moment.
I'm guessing that the ActiveRecord::Base has some method that will return the query object as opposed to executing it, but I haven't found that in the docs.
Although Rails 3 makes this significantly easier, you can always do it in Rails 2 with a little hack that emulates it:
# config/initializers/rails2_where_scope.rb
class ActiveRecord::Base
named_scope :where, lambda { |conditions| {
:conditions => conditions
}}
end
This way you can chain together multiple conditions in a manner that's forward-compatible with Rails 3:
query2 = Table.where(condition1).where(condition2).all
Rails 3 uses AREL to do most of the SQL computations so that's why it's much more flexible than Rails 2.

Rails: default scoping being cached by query cache?

I got a default scoping like this which is dynamic:
default_scope :conditions => ["departure_date >= ?", DateTime.current.beginning_of_day]
When I use this code the first day is ok. Lets say first day is 28-03-2011
But the next day seems like it's still using "departure_date >= 28-03-2011"
Is my default scoping being cached?
The problem is that that code is only being executed once, when your app is loaded, and thus the actual date isn't changing. You need to change it to load lazily:
default_scope lambda { { :conditions => ["departure_date >= ?", DateTime.current.beginning_of_day] } }
This way, Datetime.current.beginning_of_day will be evaluated each time you make a query.

Rails: Benchmarking rails ActiveRecord Queries

I'm looking to benchmark a couple of my ActiveRecord requests in my app. What's the simplest way in the console to benchmark something like
User.find_by_name("Joe").id
versus
User.find(:first, :select => :id, :conditions => ["name = ?","Joe"]).id
Thanks
This question is a bit old and needs an updated answer. The easiest way to benchmark the query outside of a production scenario would be to run it in rails console (the benchmarker script isn't in Rails anymore.) Then you can simply test using the Benchmark class built into Ruby. Run the following in Rails:
puts Benchmark.measure { User.find_by_name("Joe").id }
puts Benchmark.measure { User.find(:first, :select => :id, :conditions => ["name = ?","Joe"]).id }
I'd run the above 5 times, discard the min and max, and take the average cost of the remaining three runs to figure out which query is going to give you better performance.
This is the most accurate solution to get the true cost of a query since Rails doesn't show you the cost to actually construct your objects. So while #Slobodan Kovacevic answer is correct in that the log shows you how log the query takes, the long doesn't give you object construction time which may be less for your second query since you're only populating a single field vs all the user fields.
In development mode each query is timed and logged in log/development.log. You'll have lines like:
Ad Load (1.4ms) SELECT "ads".* FROM "ads" ORDER BY created_at DESC
Use script/performance/benchmarker:
script/performance/benchmarker 2000 "User.find_by_name('Joe').id" "User.first(:conditions => {:name => 'Joe'}, :select => 'id').id"
On my dev machine, this reports:
user system total real
#1 1.110000 0.070000 1.180000 ( 1.500366)
#2 0.800000 0.050000 0.850000 ( 1.078444)
Thus, the 2nd method appears to be faster, since it has less work to do. Of course, you should benchmark this on your production machine, using the production environment:
RAILS_ENV=production script/performance/benchmarker 2000 "User.find_by_name('Joe').id" "User.first(:conditions => {:name => 'Joe'}, :select => 'id').id"
It might change conditions a bit for you.

"Section" has_many versioned "Articles" -- How can I get the freshest subset?

I have a Model called Section which has many articles (Article). These articles are versioned (a column named version stores their version no.) and I want the freshest to be retrieved.
The SQL query which would retrieve all articles from section_id 2 is:
SELECT * FROM `articles`
WHERE `section_id`=2
AND `version` IN
(
SELECT MAX(version) FROM `articles`
WHERE `section_id`=2
)
I've been trying to make, with no luck, a named scope at the Article Model class which look this way:
named_scope :last_version,
:conditions => ["version IN
(SELECT MAX(version) FROM ?
WHERE section_id = ?)", table_name, section.id]
A named scope for fetching whichever version I need is working greatly as follows:
named_scope :version, lambda {|v| { :conditions => ["version = ?", v] }}
I wouldn't like to end using find_by_sql as I'm trying to keep all as high-level as I can. Any suggestion or insight will be welcome. Thanks in advance!
I would take a look at some plugins for versioning like acts as versioned or version fu or something else.
If you really want to get it working the way you have it now, I would add a boolean column that marks if it is the most current version. It would be easy to run through and add that for each column and get the data current. You could easily keep it up-to-date with saving callbacks.
Then you can add a named scope for latest on the Articles that checks the boolean
named_scope :latest, :conditions => ["latest = ?", true]
So for a section you can do:
Section.find(params[:id]).articles.latest
Update:
Since you can't add anything to the db schema, I looked back at your attempt at the named scope.
named_scope :last_version, lambda {|section| { :conditions => ["version IN
(SELECT MAX(version) FROM Articles
WHERE section_id = ?)", section.id] } }
You should be able to then do
section = Section.find(id)
section.articles.last_version(section)
It isn't the cleanest with that need to throw the section to the lambda, but I don't think there is another way since you don't have much available to you until later in the object loading, which is why I think your version was failing.

Better Performance on Associations

Right now I have a table called Campaigns that has many Hits, if I call say:
Campaign.find(30).hits
Which takes 4 seconds, or 4213 ms.
If I call this instead:
campaign = Campaign.find(30)
campaign.hits.count
Does it still load all of the hits, then count? Or does it see I am counting and avoids loading all of the hits? (Which is currently 300,000+ rows).
I am trying to figure out a smart way to load/count my hits. I am thinking about adding a method to my Campaign.rb model, like:
def self.total_hits
find :first, :select => 'COUNT(id) as hits', :conditions => ["campaign_id = ?", self.id]
end
I know that query won't load from the hits table, but that is just an example of counting it from a self made query, apposed to Ruby on Rails doing this for me.
Would this memcache query be more effecient? (I have it running, but doesn't seem to be any better/faster/slower, just the same speed.)
def self.hits
Rails.cache.fetch("Campaign_Hits_#{self.campaign_id}", :expires_in => 40) {
find(:first, :select => 'COUNT(id) as hits', :conditions => ["campaign_id = ?", self.campaign_id]).hits
}
end
Any suggestions would be great!
How about:
Campaign.find(30).hits.count
You might also consider adding the following in hit.rb (assuming a one-to-many relationship between campaigns and hits).
belongs_to :campaign, :counter_cache => true
You then need a column in the campaigns table called hits_count. This will avoid hitting hits altogether if you're only getting the count.
You can check the API for the full rundown.
My ActiveRecord might be a little rusty, so forgive me if so, but IIRC Campaign.find(30).hits is at least two separate queries. How does Campaign.find(30, :include => [ :hits ]).hits do? That should perform a single query.

Resources