rails complex form and ordering with build - ruby-on-rails

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

Related

Rails 4 - Grouping ActiveRecord items based on associated models

I have a Rails 4 app, where I am making a table that shows me what items I have in stock. Items that are not in stock are NOT displayed.
In my controller I do the following:
#stock = Stock.all
And In my view I have this:
<table>
<% #stock.each do |item| %>
<tr>
<td><%= item.id %></td>
<td><%= item.product.id %></td>
<td><%= item.product.description %></td>
</tr>
<% end %>
</table>
This is the outcome:
+---------------------------------------------+
| Stock ID | Product ID | Product description |
+---------------------------------------------+
| 1 | 63 | A cool wheel |
+---------------------------------------------+
| 2 | 63 | A cool wheel |
+---------------------------------------------+
| 3 | 63 | A cool wheel |
+---------------------------------------------+
| 4 | 26 | A red coat |
+---------------------------------------------+
| 5 | 26 | A red coat |
+---------------------------------------------+
| 6 | 99 | Something |
+---------------------------------------------+
| ... | ... | ... |
But I would like to have it grouped by amount. How could I achieve that?
This is what I would like to get
+---------------------------------------------+
| Amount | Product ID | Product description |
+---------------------------------------------+
| 3 | 63 | A cool wheel |
+---------------------------------------------+
| 2 | 26 | A red coat |
+---------------------------------------------+
| 1 | 99 | Something |
+---------------------------------------------+
| ... | ... | ... |
I thought this would do it, but it did not work:
.count(:all, group: "product_id")
ActiveRecord has a group function.
How to use it you can find it in the guides: http://guides.rubyonrails.org/active_record_querying.html#group
Hey you can try this way
#stock = Stock.joins(:product).select("count(product_id) as amount,products.id as product_id, products.description as product_description").group("product_id")

How to join with a polymorphic model using the PublicActivity gem

I'm using the PublicActivity gem: https://github.com/pokonski/public_activity
All of the models I use PublicActivity to track use the column edition_id. And I'm wondering how I can scope by that column since it's polymorphic relation.
Eg PublicActivity looks like so:
PublicActivity::Activity.limit(50)
+----+--------------+----------------+----------+------------+--------------------+------------+--------------+----------------+---------------------------+---------------------------+
| id | trackable_id | trackable_type | owner_id | owner_type | key | parameters | recipient_id | recipient_type | created_at | updated_at |
+----+--------------+----------------+----------+------------+--------------------+------------+--------------+----------------+---------------------------+---------------------------+
| 1 | 42 | QuizMaster | 6 | User | quiz_master.update | {} | | | 2013-04-12 17:33:14 +0100 | 2013-04-12 17:33:14 +0100 |
| 2 | 25 | Place | 6 | User | place.update | {} | | | 2013-04-12 17:42:42 +0100 | 2013-04-12 17:42:42 +0100 |
| 3 | 25 | Event | 6 | User | event.update | {} | | | 2013-04-12 17:45:08 +0100 | 2013-04-12 17:45:08 +0100 |
| 4 | 20 | QuizMaster | 6 | User | quiz_master.update | {} | | | 2013-04-12 17:49:09 +0100 | 2013-04-12 17:49:09 +0100 |
| 5 | 20 | QuizMaster | 6 | User | quiz_master.update | {} | | | 2013-04-12 17:50:51 +0100 | 2013-04-12 17:50:51 +0100 |
+----+--------------+----------------+----------+------------+--------------------+------------+--------------+----------------+---------------------------+---------------------------+
Where edition_id is on the polymorphic trackable relation.
What I would like to do it something like:
PublicActivity::Activity.limit(50).includes(:trackable)# where trackable edition = 1
I'm not sure how or even if it's possible to join or include or preload a polymorphic model across multiple "trackable" types.
I don't think this is possible directly with SQL because of the polymorphism, but you could do something with ruby pretty easily.
PublicActivity::Activity.limit(50).select {|c| c.trackable.edition_id = 1 }
It won't be as efficient as a SQL query but using Rails preload it'll probably be good enough depending on the number of records you're fetching.
PublicActivity::Activity.limit(50).preload(:trackable).select {|c| c.trackable.edition_id = 1 }

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 simple_form association issue

I'm having a difficult time getting the :association helper to work. Basically I want to have a select box with all 32 teams and instead of an unhelpful :team_id number, I want to use ActiveRecord magic to show the 'abbr' or 'city' from the appropriate Team instead. I'm using a MySQL DB btw.
Models
class Player < ActiveRecord::Base
belongs_to :teams
end
class Team < ActiveRecord::Base
has_many :players
end
Controller
#player = Player.find(params[:id])
View
<%= simple_form_for #player do |f| %>
<%= f.input :first %>
<%= f.input :last %>
<%= f.association :teams %>
<%= f.button :submit %>
<% end %>
==================
Just to help visualize the data here is a sampling of the data as it appears in the database.
Database - Teams
+----+-----------+-----------+---------------------+---------------------+------+
| id | city | name | created_at | updated_at | abbr |
+----+-----------+-----------+---------------------+---------------------+------+
| 1 | Arizona | Cardinals | 2013-08-27 17:23:55 | 2013-08-27 17:23:55 | ARI |
| 2 | Atlanta | Falcons | 2013-08-27 17:23:55 | 2013-08-27 17:23:55 | ATL |
| 3 | Baltimore | Ravens | 2013-08-27 17:23:55 | 2013-08-27 17:23:55 | BAL |
| 4 | Buffalo | Bills | 2013-08-27 17:23:55 | 2013-08-27 17:23:55 | BUF |
+----+-----------+-----------+---------------------+---------------------+------+
Database - Players
+----+---------+----------+--------+-----------------+---------------------+---------------------+
| id | team_id | position | first | last | created_at | updated_at |
+----+---------+----------+--------+-----------------+---------------------+---------------------+
| 1 | 5 | QB | Derek | Anderson | 2013-08-26 18:48:59 | 2013-08-27 20:41:37 |
| 2 | 24 | QB | Matt | Barkley | 2013-08-26 18:48:59 | 2013-08-26 18:48:59 |
| 3 | 18 | QB | McLeod | Bethel-Thompson | 2013-08-26 18:48:59 | 2013-08-26 18:48:59 |
| 4 | 6 | QB | Matt | Blanchard | 2013-08-26 18:48:59 | 2013-08-26 18:48:59 |
| 5 | 26 | QB | Sam | Bradford | 2013-08-26 18:48:59 | 2013-08-26 18:48:59 |
+----+---------+----------+--------+-----------------+---------------------+---------------------+
First of all, you should be using singular for belongs_to, not plural. So your model becomes
class Player < ActiveRecord::Base
belongs_to :team
end
...and your form input also in the singular, with abbr as the displayed field in your select and id as the actual value that's passed on to your params:
<%= f.association :team, :label_method => :abbr, :value_method => :id
pass a label_method.
like
<%= f.association :team, label_method: "#{:city} #{:name}" %>
better yet, you might already have the full_name functionality in place, just call that
You might have to also use the value_method option and set to team_id to properly set it if simple_form can't properly guess form the passed in association

Rails, if instance is in a scope?

I'm using rails 3 and I can't seem to check if a given instance is in a scope, see here:
p = Post.find 6
+----+----------+-------------------------+-------------------------+-------------------------+-----------+
| id | title | publish_date | created_at | updated_at | published |
+----+----------+-------------------------+-------------------------+-------------------------+-----------+
| 6 | asfdfdsa | 2010-03-28 22:33:00 UTC | 2010-03-28 22:33:46 UTC | 2010-03-28 22:33:46 UTC | true |
+----+----------+-------------------------+-------------------------+-------------------------+-----------+
I have a menu scope which looks like:
scope :menu, where("published != ?", false).limit(4)
When I run it I get:
Post.menu.all
+----+------------------+------------------+------------------+-------------------+-----------+
| id | title | publish_date | created_at | updated_at | published |
+----+------------------+------------------+------------------+-------------------+-----------+
| 1 | Lorem ipsum | 2010-03-23 07... | 2010-03-23 07... | 2010-03-28 21:... | true |
| 2 | fdasf | 2010-03-28 21... | 2010-03-28 21... | 2010-03-28 21:... | true |
| 3 | Ruby’s Imple... | 2010-03-28 21... | 2010-03-28 21... | 2010-03-28 21:... | true |
| 4 | dsaD | 2010-03-28 22... | 2010-03-28 22... | 2010-03-28 22:... | true |
+----+------------------+------------------+------------------+-------------------+-----------+
Which is correct, but if I try to check if p is in the the menu scope using: Post.menu.exists?(p) I get true when it should be false
What is the proper way to find out if a given instance of something is in a scope?
Actually, I was able to solve it using that Array method of include? instead of exists?

Resources