Retrieving created_at value in Rails? - ruby-on-rails

Is there a way I could retrieve created_at value from the Database in Rails?
The table has columns like ticket_created, ticket_updated. By default a created_at column is also included. If I try doing:
#tickets = Ticket.find(:all)
for ticket in #tickets
puts ticket.created_at
end
the above code is returning ticket_created instead of the automatically generated created_at
The sample database row looks like this.
id | title | link | key | summary | priority | status | created_at | updated_at | ticket_created | ticket_updated

Try this to really put yourself at ease that the two columns contain different values.
Ticket.find(:all).map {|t|
{:attributes => t.attributes,
:created_at => t.created_at,
:ticket_created => t.ticket_created}
}.inspect
Then try t.created_at == t.ticket_created to make sure they aren't equal and then lastly, rename the ticket_created column to something_else and see if that does the trick.

Related

How to write method for auto update one column based on the other column in the same row rails

I have a Users table like this:
-----------------------------------------------
| name | email | role | card_amount (integer) |
-----------------------------------------------
| ... | ... | ... | ... |
-----------------------------------------------
I want to update the role column based on the card_amount column automatically with a specific condition like below:
if #user.card_amount >= 100
Then the role column will auto update like:
#user.role = "buyer"
How to make it happens automatically? So everytime the #user.card_amount >= 100 the role colum will have value "buyer".
Or when I go to rails console and update the card_amount to 100, then the role column will also being updated to "buyer"?
You should use a before_save callback. eg
before_save :update_role
def update_role
if self.card_amount >= 100
self.role = "buyer"
end
end
Read this: http://guides.rubyonrails.org/active_record_callbacks.html

Get model id where(value==x)

I have what I have to imagine is a profoundly simple question but I haven't been able to find the answer after quite a bit of Googling.
Say I have a user and each user has_one widget. Now the widget table is set up as follows:
mysql> show columns in widgets;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| user_id | int(11) | YES | MUL | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
I want to look up the widget's id by using the user_id and store it as #id in my controller.
I've tried several variations of the following without success:
#widget=Widget.where(:user_id => current_user)
#id=#widget.id
I sort of feel embarrassed asking something this simple but I really couldn't find a straight answer. Many thanks in advance.
Widget.where(:user_id => current_user.id) returns a collection of all widgets belonging to user - it does not take in account the has_one association defined on model, because DB could contain other records for one reason or another.
What you need is the first matching record - Widget.where(:user_id => current_user.id).first. Or simply current_user.widget, to use the association.
If you just one the current user's widget you can use the following:
#widget = current_user.widget
This will use the has_one relationship that you defined.
For a different user:
#widget = some_other_user.widget
You can use the normal ActiveRecord methods in case you jut have the user_id. In that case you can just save the query that gets the user:
#widget = Widget.where(user_id: some_user_id).first
In all the cases you have to be careful, because in both cases #widget can be nil when nothing is found in the database.
You are slight correct, but think this is the way:
#id = Widget.where(user_id: current_user.id).first.try(:id)
So you have to select a widget for specified user_id, then selects first value (if any), and returns id or nil.
In where query always gives array
#widget=Widget.where(:user_id => current_user).first
#widget.id
You can directly use association between user and widget to find widget id, like this:
current_user.widget.try(:id)
try is required for nil value if the current user don't have any widget then current_user.widget will return nil.

Postgres - How to create index for simple association directly (outside of activerecord)?

We have a Postgres database that is populated through a node app that parses XML and loads our dataset for us.
We have built a Sinatra app to view the data. We have a number of archive_objects which have a number of tags.
We have associated the two classes via their models, eg:
class ArchiveObject < ActiveRecord::Base
has_and_belongs_to_many :tags
end
class Tag < ActiveRecord::Base
has_and_belongs_to_many :archive_objects
end
We have noticed that calling, for example current_archive_object.tags is quite slow (400+ms on average), and after reading Using indexes in rails: Index your associations, I see the recommendation to create the index for this simple association in the ActiveRecord migration (names modified for relevance here):
add_index :tags, :archive_object_id, :name => 'archive_object_id_idx'
I'm wondering, how can I create this index directly in psql since our database is not generated through an AR migration?
EDIT:
Information regarding our 'junction table', should it be relevant
\d+ archive_objects_tags
Table "public.archive_objects_tags"
Column | Type | Modifiers | Storage | Stats target | Description
-------------------+--------------------------+-----------+---------+--------------+-------------
created_at | timestamp with time zone | not null | plain | |
updated_at | timestamp with time zone | not null | plain | |
tag_id | integer | not null | plain | |
archive_object_id | integer | not null | plain | |
Indexes:
"archive_objects_tags_pkey" PRIMARY KEY, btree (tag_id, archive_object_id)
Has OIDs: no
And the SQL call from the rack console:
Tag Load (397.4ms) SELECT "tags".* FROM "tags" INNER JOIN "archive_objects_tags" ON "tags"."id" = "archive_objects_tags"."tag_id" WHERE "archive_objects_tags"."archive_object_id" = $1 [["archive_object_id", 4823]]
From the PostgreSQL docs, the equivalent to
add_index :tags, :archive_object_id, :name => 'archive_object_id_idx'
would be:
CREATE UNIQUE INDEX archive_object_id_idx ON tags (archive_object_id);
I don't believe that is what you want in your case, because your tags table does not have an archive_object_id column. You probably want to create a multicolumn index on your "junction table".
CREATE UNIQUE INDEX archive_objects_tags_tag_id_archive_object_id_idx ON archive_objects_tags (archive_object_id, tag_id);

Will Paginate can order by certain columns but not by other columns on Model

I am doing some maintenance on a Rails 2 application using Ruby 1.8.7. I am using will_paginate.
I have the following problem:
When calling current_user.products.paginate(:page => 1, :order => "updated_at asc") it orders, as expected, based on the updated_at property in products.
However, when calling current_user.products.paginate(:page => 1, :order => "released_at asc") it does not order on released_at as expected. In fact it doesn't matter whether I specify ordering to happen according to "asc" or "desc", I get the same collection returned.
updated_at and released_at are both attributes defined on the model and exists in the database and all values are non-null. There is no default_scope defined on the models.
What could be causing this and how to correct this?
Adding Desc products below (for brevity I am only listing the relevant fields):
| Field | Type | Null | Key | Default | Extra |
| released_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
The Product model inherits from a model that also defines the released_at attribute. The method for released_at is overloaded in the Ruby on Rails code so that if one would call product.released_at on an instance product of Product, then it would actually call the released_at value on the parent model. As a result, from the rails console it always looks as if released_at is not null and contains a value.
However, looking at the database directly shows that released_at is null in the Product model and as such, even though the will_paginate request goes through correctly, no ordering is done because the values are all the same (null). In the case where the exact same query is performed on the updated_at attribute, sorting works because that attribute is not null. I missed this because I checked for empty values from the Rails Console rather than in MySQL directly.
My solution was to define a named_scope on the Product model that sorts based on the value in the parent model. I then call the paginate function on the named scope.
Sometimes it need to have an index defined for ordering fields to make it working.

Does it make sense to convert DB-ish queries into Rails ActiveRecord Model lingo?

mysql> desc categories;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(80) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
mysql> desc expenses;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| created_at | datetime | NO | | NULL | |
| description | varchar(100) | NO | | NULL | |
| amount | decimal(10,2) | NO | | NULL | |
| category_id | int(11) | NO | MUL | 1 | |
+-------------+---------------+------+-----+---------+----------------+
Now I need the top N categories like this...
Expense.find_by_sql("SELECT categories.name, sum(amount) as total_amount
from expenses
join categories on category_id = categories.id
group by category_id
order by total_amount desc")
But this is nagging at my Rails conscience.. it seems that it may be possible to achieve the same thing via Expense.find and supplying options like :group, :joins..
Can someone translate this query into ActiveRecord Model speak ?
Is it worth it... Personally i find the SQL more readable and gets my job done faster.. maybe coz I'm still learning Rails. Any advantages with not embedding SQL in source code (apart from not being able to change DB vendors..sql flavor, etc.)?
Seems like find_by_sql doesn't have the bind variable provision like find. What is the workaround? e.g. if i want to limit the number of records to a user-specified limit.
Expense.find(:all,
:select => "categories.name name, sum(amount) total_amount",
:joins => "categories on category_id = categories.id",
:group => "category_id",
:order => "total_amount desc")
Hope that helps!
Seems like find_by_sql doesn't have the bind variable provision like find.
It sure does. (from the Rails docs)
# You can use the same string replacement techniques as you can with ActiveRecord#find
Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
Well this is the code that finally worked for me.. (Francois.. the resulting sql stmt was missing the join keyword)
def Expense.get_top_n_categories options={}
#sQuery = "SELECT categories.name, sum(amount) as total_amount
# from expenses
# join categories on category_id = categories.id
# group by category_id
# order by total_amount desc";
#sQuery += " limit #{options[:limit].to_i}" if !options[:limit].nil?
#Expense.find_by_sql(sQuery)
query_options = {:select => "categories.name name, sum(amount) total_amount",
:joins => "inner join categories on category_id = categories.id",
:group => "category_id",
:order => "total_amount desc"}
query_options[:limit] = options[:limit].to_i if !options[:limit].nil?
Expense.find(:all, query_options)
end
find_by_sql does have rails bind variable... I don't know how I overlooked that.
Finally is the above use of user-specified a potential entry point for sql-injection or does the to_i method call prevent that?
Thanks for all the help. I'm grateful.

Resources