Rails fetch row with latest update - ruby-on-rails

I have such db table structure:
id | currency_list_id | direction_id | value | updated_at
and i have such data:
1 | 1 | 1 | 8150 | 09-08-2010 01:00:00
1 | 1 | 2 | 8250 | 09-08-2010 01:00:00
1 | 2 | 1 | 8150 | 06-08-2010 01:00:00
1 | 2 | 2 | 8150 | 06-08-2010 01:00:00
1 | 1 | 1 | 8150 | 09-08-2010 15:00:00
1 | 1 | 2 | 8250 | 09-08-2010 15:00:00
so currency in exchanger is setted almost everyday, and could be setted more than one time in a day.... but also one could be setted some days ago... And i must to fetch all actual data..
How in rails (ruby) i could fetch only last actual data?
In my example result will be:
1 | 2 | 1 | 8150 | 06-08-2010 01:00:00
1 | 2 | 2 | 8150 | 06-08-2010 01:00:00
1 | 1 | 1 | 8150 | 09-08-2010 15:00:00
1 | 1 | 2 | 8250 | 09-08-2010 15:00:00
how to do this?
i try so:
#currencies = CurrencyValue.find(:all, :conditions => {:currency_list_id => id}, :order => :updated_at)
but then i will fetch all data for some currency_list_id with ordering, but how to fetch only last 2 values? How to fetch last 2 ordered rows?

#currencies = CurrencyValue.find(:all, :conditions => {:currency_list_id => id, :order => :updated_at}).last(2)
I think :). Can't check this right now.

I think what you need by be a GROUP_BY. There's another question that explains it here:
How to get the latest record in each group using GROUP BY?

Related

Rails - How to group_by with many models?

I have this chain of models:
And I have a list of suboptions. I would like to group_by the suboptions by each of the above fathers.
So, it would be divided into Categories, which would be divided into activities, which would be divided into options. Do you see?
How can I do this??
Suboptions.all.group_by(???)
# or
Suboptions.all.order_by(????)
# or ????
Example:
Suboptions
+----+-----------+
| id | option_id |
+----+-----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
| 4 | 4 |
| 5 | 3 |
+----+-----------+
Options
+----+-------------+
| id | activity_id |
+----+-------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 4 | 3 |
+----+-------------+
Activities
+----+-------------+
| id | category_id |
+----+-------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
+----+-------------+
Categories
+----+------+
| id | name |
+----+------+
| 1 | cat1 |
| 2 | cat2 |
+----+------+
then the search should return the suboptions with ids in the following order: [1,5,4,2,3]
( try to visualize it from the category to the suboption )
Depending on the size of the data set, sounds like you want to do a join, followed by an order
Suboption.joins(option: {activity: :category}).order('categories.name')
Will that work for you?

Accessing objects from many to many join table - RAILS

In ActiveRecord/Ruby on Rails if i have a many-to-many relationship set up like so:
class Blog < ActiveRecord::Base
has_many :tagged_blogposts;
has_many :tags, through: :tagged_blogposts;
end
class Tag < ActiveRecord::Base
has_many :tagged_blogposts
has_many :blogs, through: :tagged_blogposts
end
class TaggedBlogpost < ActiveRecord::Base
belongs_to :blog
belongs_to :tag
end
How do I select all the Blogs with a given tag_id ?
So far I have:
TaggedBlogposts.all.where("tag_id=?", "1"), which returns:
+----+---------+--------+-------------------------+-------------------------+
| id | blog_id | tag_id | created_at | updated_at |
+----+---------+--------+-------------------------+-------------------------+
| 2 | 1 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 4 | 2 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 7 | 3 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 15 | 6 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 17 | 7 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 24 | 9 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 33 | 13 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 36 | 15 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 46 | 18 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
| 47 | 19 | 1 | 2015-08-24 03:05:15 UTC | 2015-08-24 03:05:15 UTC |
+----+---------+--------+-------------------------+-------------------------+
But from this join table, I want to return the corresponding blog objects. Something like:
Blog.all.where(tag_id:1, through: TaggedBlogposts)
EDIT: Figured it out:
#blogs = Blog.joins(:tags).where("tags.id=?", "#{params[:tagid]}")
This should give you the expected Blogs:
Blog.joins('tagged_blogposts').where('tagged_blogposts.tag_id = ?', tag_id)
Try the below code
Blog.inlcudes(:tagged_blogposts).where('tagged_blogposts.tag_id = ?', 1).references(:tagged_blogposts)
First find tag record:
tag = Tag.find tag_id
and then you can get all blogs for this tag using:
tag.blogs

Rails - Get Column Value with Group By

I have the following tables with entries that might look like:
Table: sessions
ID | CREATED_AT | UPDATED_AT | USER_ID | GROUP_ID
---|-------------------------|-------------------------|---------|----------
27 | 2014-07-01 23:02:16 | 2014-07-01 23:03:18 | 1 | 1
28 | 2014-07-02 16:55:25 | 2014-07-02 17:31:40 | 1 | 2
29 | 2014-07-07 20:31:13 | 2014-07-07 20:34:17 | 1 | 3
Table: groups
ID | NAME | CREATED_AT | UPDATED_AT
---|-------------------|-------------------------|------------------------
1 | Marching | 2013-12-17 19:45:28 | 2013-12-17 19:45:28
2 | Reaching | 2014-02-07 17:29:59 | 2014-02-07 17:29:59
3 | Picking | 2014-03-11 21:38:56 | 2014-03-11 21:38:56
And I have the following query in Rails:
Session.joins(:group).select('groups.name').where(:user_id => 1).group('sessions.group_id').count
Which returns the following keys and values:
=> {2=>7, 1=>3, 3=>1} (The "key" is the group_id and the "value"
is the # of times it occurs).
My question is: Instead of returning the "id" as the key, is it possible for me to return the groups.name instead? Which would look like:
=> {"Reaching"=>7, "Marching"=>3, "Picking"=>1}
If not, would I have to loop through and re-query again based on each group_id?
Thanks very much.
This should work if you have everything set up in your models.
data = Group.joins(:sessions).select('name, count(*) as occurrence_count').where('sessions.user_id = ?', 1).group('groups.name')
Then you can access it like this
data.first.occurrence_count

Generate unique id for a new item in models on Rails 3

I populate book items into my Book model,
But I found there are many items have the same id.
So, how to create unique id for items. To prevent many items from having the same id ?
Here is the book model code
# encoding: utf-8
class Book < ActiveRecord::Base
attr_accessible :name, :isbn ,:price ,:comment ,:author ,:sale_type ,:publisher ,:sn ,:category
attr_accessible :location, :category, :release_date
validates_uniqueness_of :sn
Here are the part of my items
irb(main):058:0> Book.all[1..10]
+-----+------+-----+-----+------+------+-----+------+-----+-----+------+------+-----+------+
| id | pric | com | cre | upda | rele | loc | sn | isb | aut | sale | name | cat | publ |
+-----+------+-----+-----+------+------+-----+------+-----+-----+------+------+-----+------+
| 118 | 4543 | 作 | 201 | 2013 | 2006 | --- | 2124 | 978 | 趙 | prom | 求索 | 商 | 聯經 |
| 118 | 872 | 馬 | 201 | 2013 | 2013 | --- | 2124 | 978 | 黎 | prom | 告別 | 政 | 聯經 |
| 118 | 2105 | 某 | 201 | 2013 | 2012 | --- | 2124 | 978 | 吳 | prom | 複眼 | 政 | 夏日 |
| 118 | 301 | 作 | 201 | 2013 | 2006 | --- | 2124 | 978 | 王 | norm | 天香 | 歷 | 麥田 |
| 118 | 411 | 少 | 201 | 2013 | 2008 | --- | 2124 | 978 | 韓 | norm | 鞋癖 | 商 | 聯經 |
| 119 | 3751 | 有 | 201 | 2013 | 2010 | --- | 2124 | 978 | 紀 | prom | 私家 | 體 | 印刻 |
| 119 | 3361 | 文 | 201 | 2013 | 2010 | --- | 2124 | 978 | 林 | fix_ | 我不 | 體 | 印刻 |
| 119 | 1140 | 何 | 201 | 2013 | 2012 | --- | 2124 | 978 | 邁 | norm | 正義 | 體 | 雅言 |
| 119 | 888 | 一 | 201 | 2013 | 2007 | --- | 2124 | 978 | 福 | fix_ | 生命 | 商 | 究竟 |
| 119 | 3283 | 近 | 201 | 2013 | 2011 | --- | 2124 | 978 | 芮 | norm | 海拉 | 政 | 遠流 |
+-----+------+-----+-----+------+------+-----+------+-----+-----+------+------+-----+------+
here the rake code to generate my data
16 bk = Book.new(:sn => real_sn,:name => book_name, :isbn=>isbn,
17 :price =>Random.rand(200..5000), :location=>location, :category=>["商業","歷史","體育","政治"].sample,
18 :author => author, :sale_type => [:fix_priced, :normal, :promotion].sample, :publisher => publisher,
19 :release_date => rand(10.years).ago, :comment => comment
20 )
Columns in the table I use the Postgre DB
Column | Type | Modifiers
--------------+-----------------------------+----------------------------------------------------
id | integer | not null default nextval('books_id_seq'::regclass)
price | integer |
comment | text |
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
release_date | text |
location | text |
sn | bigint |
isbn | bigint |
author | text |
sale_type | text |
name | text |
category | text |
publisher | text |
Indexes:
"books_pkey" PRIMARY KEY, btree (id)
The code above, does not save any record in the database, it just instantiate objects of Book model. You should either save the object after initialization bk.save or use the create method instead of new.
bk = Book.new(:sn => real_sn,:name => book_name, :isbn=>isbn,
:price =>Random.rand(200..5000), :location=>location,
:category=>["商業","歷史","體育","政治"].sample, :author => author,
:sale_type => [:fix_priced, :normal, :promotion].sample,
:publisher => publisher, :release_date => rand(10.years).ago,
:comment => comment)
bk.save
Or alternatively you can use the create method
bk = Book.create(:sn => real_sn,:name => book_name, :isbn=>isbn,
:price =>Random.rand(200..5000), :location=>location,
:category=>["商業","歷史","體育","政治"].sample, :author => author,
:sale_type => [:fix_priced, :normal, :promotion].sample,
:publisher => publisher, :release_date => rand(10.years).ago,
:comment => comment)
Once saved in the database, it will automatically gain a unique id.

rails complex form and ordering with build

I have complex form similar to a recent Ryan Bates screencast
The nested elements work fine however. I'm creating or updating a grid of data such as this through a form where the day's prices are the input. My problem begins when they leave one blank. I have the nested_attributes_for option for not saving nils and it works, if they only save one value in a particular row, it saves the correct day however when reloaded, it will place it in the wrong column. I'm not sure how to order the values in a row to the form. IE A saved value for wednesday will appear in the monday column (of the correct row). This doesn't happen if they save all value for a row (then it works perfectly).
Data is stored in the DB like so
ID OBJECT_ID DAYOFWEEK PRICE and displaying like below
+------+----------------+-------+-------+-------+------+-------+
| id | name | Mon | Tue | Wed | Thu | Fri | -> +2 more days etc
+------+----------------+-------+-------+-------+------+-------+
| 1234 | Some name | 87.20 | 87.20 | 87.20 | 82.55| 85.48 |
+------+----------------+-------+-------+-------+------+-------+
| 1234 | Some name | 87.20 | 87.20 | 87.20 | 82.55| 85.48 |
+------+----------------+-------+-------+-------+------+-------+
| 1234 | Some name | 87.20 | 87.20 | 87.20 | 82.55| 85.48 |
+------+----------------+-------+-------+-------+------+-------+
The controller code either building or display these values is like so:
controller
#rooms.each do |r|
((r.room_rates.size+1)..7).each {
r.room_rates.build
}
end
rooms.html.erb
<% #dow = 0 %>
<tr class="room">
<td><%= f.text_field :name %></td>
<% f.fields_for :room_rates do |rates| %>
<%= render 'rates', :f => rates %>
<% #dow += 1 %>
<% end %>
<td class="delete_mode" style="display:none;">
<%= f.hidden_field :_destroy %>
<%= link_to_function "remove", "remove_room(this)" %>
</td>
</tr>
rates.html.erb
<td>
<%= f.text_field :price, :size => 3 %>
<%= f.hidden_field :dayofweek, :value => #dow %>
<%= f.hidden_field :source, :value => 0 %>
</td>
room_rates model (where the data from the form is going)
+-------+---------+-----------+-------+--------+---------------------------+---------------------------+
| id | room_id | dayofweek | price | source | created_at | updated_at |
+-------+---------+-----------+-------+--------+---------------------------+---------------------------+
| 92745 | 8 | 0 | 1.0 | 0 | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92746 | 8 | 1 | 2.0 | 0 | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92747 | 8 | 2 | 3.0 | 0 | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92748 | 8 | 3 | 4.0 | 0 | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92749 | 8 | 4 | 5.0 | 0 | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92750 | 8 | 5 | 6.0 | 0 | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92751 | 8 | 6 | 7.0 | 0 | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92752 | 9 | 3 | 5.0 | 0 | 2010-02-23 14:33:33 +0100 | 2010-02-23 14:33:33 +0100 |
+-------+---------+-----------+-------+--------+---------------------------+---------------------------+
ordering in the console
+---------+-----------+-------+--------+---------------------------+---------------------------+
| room_id | dayofweek | price | source | created_at | updated_at |
+---------+-----------+-------+--------+---------------------------+---------------------------+
| 2517 | 0 | | | | |
| 2517 | 1 | | | | |
| 2517 | 2 | 3.0 | 0 | 2010-02-23 17:54:28 +0100 | 2010-02-23 17:54:28 +0100 |
| 2517 | 3 | 4.0 | 0 | 2010-02-23 17:54:28 +0100 | 2010-02-23 17:54:28 +0100 |
| 2517 | 4 | | | | |
| 2517 | 5 | | | | |
| 2517 | 6 | | | | |
+---------+-----------+-------+--------+---------------------------+---------------------------+
The error is when you create the form - because you are depending on the order of the room_rates to be correct, you need to put the empty (built) rates into the correct positions. If each room has many room rates, you need to generate the form so that the rates are at the right day in the week. This code will build that in a new array, and set the new array correctly:
#rooms.each do |r|
new_rates = []
(0..6).each { |dow|
rate = r.room_rates.find_by_dayofweek(dow)
if rate
new_rates << rate
else
new_rates << r.room_rates.build(:dayofweek => dow)
end
}
r.room_rates = new_rates
end
Alternatively, you may be able to just build the missing weeks, if you specify an order for your association:
// In room model
has_many :rates, :order => "dayofweek"
// In controller
#rooms.each do |r|
(0..6).each { |dow|
if not r.room_rates.find_by_dayofweek(dow)
r.room_rates.build(:dayofweek => dow)
end
}
end

Resources