Age-based Conditional Statements in Rails 3 - ruby-on-rails-3

--still learning rails here.. I want to write a conditional statement such as:
if variable.created_at.method_for_checking_if_older_than(10 minutes)
#code
end
What statement or method can i use on a created_at value to fulfil the purpose of checking if it is older than a certain number of minutes/hours etc..?

You're looking for this:
if variable.created_at < 10.minutes.ago
#code
end
Rails adds several such methods to the standard Ruby Numeric class, a full list is available from the Rails API documentation:
http://api.rubyonrails.org/classes/Numeric.html

Related

How to write an SQL NOT EXISTS query/scope in the Rails way?

I have a database scope to filter only latest ProxyConfig version for particular Proxy and environment.
This is the raw SQL that works very well with MySQL, PostgreSQL and Oracle:
class ProxyConfig < ApplicationRecord
...
scope :current_versions, -> do
where %(NOT EXISTS (
SELECT 1 FROM proxy_configs pc
WHERE proxy_configs.environment = environment
AND proxy_configs.proxy_id = proxy_id
AND proxy_configs.version < version
))
end
...
end
You can find a simple test case in my baby_squeel issue.
But I find it nicer not to use SQL directly. I have spent a lot of time trying out different approaches to write it in the Rails way to no avail. I found generic Rails and baby_squeel examples but they always involved different tables.
PS The previous version used joins but it was super slow and it messed up some queries. For example #count produced an SQL syntax error. So I'm not very open on using other approaches. Rather I prefer to know how to implement this query exactly. Although I'm at least curious to see other simple solutions.
PPS About the question that direct SQL is fine. In this case, mostly yes. Maybe all RDBMS can understand this quoting. If one needs to compare text fields though that requires special functions on Oracle. On Postgres the case-insensitive LIKE is ILIKE. It can be handled automatically by Arel. In raw SQL it would require different string for the different RDBMS.
This isn't actually a query that you can build with the ActiveRecord Query Interface alone. It can be done with a light sprinkling of Arel though:
class ProxyConfig < ApplicationRecord
def self.current_versions
pc = arel_table.alias("pc")
where(
unscoped.select(1)
.where(pc[:environment].eq(arel_table[:environment]))
.where(pc[:proxy_id].eq(arel_table[:proxy_id]))
.where(pc[:version].gt(arel_table[:version]))
.from(pc)
.arel.exists.not
)
end
end
The generated SQL isn't identical but I think it should be functionally equivilent.
SELECT "proxy_configs".* FROM "proxy_configs"
WHERE NOT (
EXISTS (
SELECT 1 FROM "proxy_configs" "pc"
WHERE "pc"."environment" = "proxy_configs"."environment"
AND "pc"."proxy_id" = "proxy_configs"."proxy_id"
AND "pc"."version" > "proxy_configs"."version"
)
)

Rails 3 update_all with condition in console

I have a Rails 3.2.14 app with a Facility model and I need to update the region_id in the Facility model based on a field called facility_name.
So I'm trying to update all Facilities where facility_name starts with DFW.
In the console I tried this:
Facility.where("facility_name: ilike 'DFW'")
This gives me nil or a 0 record return.
I'd like to be able to do something like this to update the region_id in the Facility model:
Facility.where("facility_name: ilike 'DFW'").update_all(region_id: '1')
But this doesn't work because my where method reports a 0 count even though there are plenty of records with the facility_name beginning with DFW.
Is my syntax wrong or is this not possible to do in Rails 3? If not, how would I go about updating over 100 records with this region id without doing it using crud/rails_admin?
I asked a similar question on how to use update_all but it didn't cover the conditional part. Hope this is not considered a duplicate.
It looks like you're kinda mixing up syntax.
When you put a where condition in a string, you need to conform to the syntax of your database adapter. So for postgres which has ilike, you need to do:
Facility.where("facility_name ilike 'DFW'")
The colon is used when you pass a hash instead, but one can't do like statements:
Facility.where(facility_name: 'DFW')
Note that if you want the ilike to check for any rows that contain that value in the column, you need trailing & leading percent signs.
Facility.where("facility_name ilike '%DFW%'")
From there you can perform the update_all

how do I write SQL in a ruby method?

I would like to have a method called feed in my User model that returns all the entries from two tables (discussions, exchanges).
In User.rb
def feed
SELECT * FROM discussions, exchanges GROUP BY created_at
end
This doesn't work, i get a problem in rails console
syntax error, unexpected ';', expecting '='
Can anyone show me how to write SQL in here? Basically I want to return and sort entries from two different tables..
if you want actual ActiveRecord objects you can try the following
def feed
exchanges = Exchange.all
discussions = Discussion.all
(exchanges + discussions).sort! { |a, b| a.created_at <=> b.created_at }
end
this is quite ineffective, as the sorting could be done in sql, but ActiveRecord cannot instantiate records selected from different tables (you can somehow override this by using STI)
Firstly - you can't just write plain SQL in your ruby code and expect it to work.
It's ruby, not SQL. They are different languages.
If you can - use the ruby-way with associations instead (as per the other example).
However - if you desperately need to use raw SQL (eg you have legavy tables that don't match to models or have some complex combination-logic in teh SQL that doesn't easily map to assocations); then you need to pass SQL to the database... which means using a connection via Active Record.
Try:
def feed
ActiveRecord::Base.connection.execute("SELECT * FROM discussions, exchanges GROUP BY created_at")
end
It will not return ruby models for you - just a raw results-object.
I'd recommend trying this in script/console and then doing a "puts my_user.feed.inspect" to have a look at the kind of thing it returns so you know how to use it.
Note: the presence of this kind of thing is considered a strong code smell - only use it where you really need it

Is there a more database agnostic way to write this default scope in Rails 3?

I have the following default scope defined in one of my models
default_scope order("IF(format = #{FORMATS[:wide]}, 1, 0) DESC, created_at DESC, name ASC")
It worked fine on my dev machine where I'm running MySQL, but borked when deployed to production where we use postgres. Is there a way to write that using Arel instead of straight SQL? FORMATS[:wide] returns an integer, but it may not be in any particular order. I just want records with that particular format to be returned first.
I wouldn't put that in SQL at all. I would probably make a scope for each format type and then use Ruby to determine which to use. Or create a method that determines the sort order and passes that to wherever you are using it.

Ruby on Rails: getting the max value from a DB column

Currently I can make the straight-up SQL query on my DB:
SELECT MAX(bar) FROM table_name
And it returns with the max value in that table. When I make what I consider to be an equivalent call in Rails, however, it does not work. I am calling:
Bar.all(:select => "Max(bar)")
This simply returns with:
[#<Bar >]
In the column I'm calling on is a series of identifying numbers, I'm looking for the largest one. Is there some other way of accessing this in Rails?
Assuming your model name is Bar and it has a column named bar, this should work:
Bar.maximum(:bar)
See the excellent Rails Guides section on Calculations :: Maximum for more info.
one more way
Bar.select("Max(bar) as max_bar").first.max_bar