「rails」日付型について
Time型
今日
Time.now:2014-01-04 08:41:51 +0900→Time型
初月
Time.now.beginning_of_month
=> 2014-01-01 00:00:00 +0900 →Time型
末月
Time.now.end_of_month
日時指定
now_time = Time.now
Time.new(now_time.year, now_time.month, now_time.day, office.open_hour.to_i, office.open_min.to_i-1, 59)
本日の開始日時Time.now.beginning_of_day
=> 2014-01-04 00:00:00 +0900→Time型
Time.now.end_of_day
Date型
今日
Date.today
明日
Date.tomorrow
昨日
Date.yesterday
時間切り取り
Time.now.strftime("%H:%M:%S")
=> "11:03:52"→string型
例えば営業時間内か調べる
Time.now.strftime("%H:%M:%S").between?(self.open_time.strftime("%H:%M:%S"),self.close_time.strftime("%H:%M:%S"))
「rails」モジュールにアクセスする
いつも忘れるのでメモ
module ColorType
TOKYO = 1
OSAKA = 2
NAGOYA = 3
HUKUOKA = 4
NATIONAL = 5
VIETNAM = 6
DEFALT = 7
NAME = {
TOKYO => "red",
OSAKA => "yellow",
NAGOYA => "green",
HUKUOKA => "purple",
NATIONAL => "blue",
VIETNAM => "grey",
DEFALT => "blue"
}.freeze
end
Office::ColorType::NAME
=> {1=>"red", 2=>"yellow", 3=>"green", 4=>"purple", 5=>"blue", 6=>"grey", 7=>"blue"}
Office::ColorType::NAME.keys
=> [1, 2, 3, 4, 5, 6, 7]
Office::ColorType::NAME.values
=> ["red", "yellow", "green", "purple", "blue", "grey", "blue"]
Office::ColorType::NAME[1]
=> "red"
Office::ColorType::DEFALT
=> 7
Office::ColorType::NAME[Office::ColorType::DEFALT]
=> "blue"
これがなんか気持ち悪いんだよな。。。
なんかいい方法はないかな
「rails」アソシエーションについて
Associationsとは
テーブルとテーブルの関連付けのこと
アソシエーションで大切な事
・命名規則
外部キー列は、「参照先モデル_id」の形式
中間テーブルは参照先テーブルを「_」で、辞書順に連結
※
アソシエーションの種類
belongs_tohas_onehas_manyhas_many :throughhas_one :throughhas_and_belongs_to_many
belongs_to:
一つのインスタンスが他のモデルの1つのモデルのインスタンスにぞくしている。ときに使用する。
条件:
・belongs_toの場合単数形でなければならない。
・belongs_toを付けたモデルに関連モデルに紐づくidを書く
複数形にしてしまった場合
uninitialized constant Order::Customersというエラーがでる。
値の取り方:
order = Order.find(2)
Order id: 2, customer_id: 2, order_date: nil, created_at: "2013-12-14 02:08:17", updated_at: "2013-12-14 02:08:17"
order.customer
Customer id: 2, name: "佐々木", created_at: "2013-12-14 02:02:06", updated_at: "2013-12-14 02:02:06"
また、ユーザーのnameだけ表示したいと言うときは
order.customer.name
"佐々木"
と使います。
この注文は誰が注文したかを抽出するときに使います。
ではorder.customersを実行してみました。
NoMethodError: undefined method `customers'
上記エラーがかえってきました。
逆に佐々木ってゆうユーザーは何を注文したのか調べたい。っておもったので、とりあえず
cusomer.order
結果→undefined method `order'
エラーになる。。。
そこで登場するのがhas_oneです。
has_oneとはモデルの各インスタンスが、他のモデルの1つのインスタンスをもっている状態のことです。なのでhas_oneは1:1の関係ということになります。
条件:
belongs_toと反対のモデルに定義する
状態:
1:1の関係
has_oneを行う場合のモデルは
order
class Order < ActiveRecord::Base
belongs_to :customer
end
customer
class Customer < ActiveRecord::Base
has_one :order
end
今回の例はあまりよろしくないのですが、一人のユーザーは一回しかオーダーできないと仮定して、
cusomer.orderをすると
Order id: 2, customer_id: 2, order_date: nil, created_at: "2013-12-14 02:08:17", updated_at: "2013-12-14 02:08:17"
が取得できるようになりました。
has_many アソシエーション
次は1:多の関係についてです。
has_manyアソシエーションは
各インスタンスには他モデルのインスタンスを0以上持っていることを示します。
次の例は1カスタマーは複数のオーダーを持っている状態です。
条件:
1.belong_toと反対のモデルに定義する
2.has_manyの場合、複数形にする
3.viewに表示する場合、繰り返し文を使用する必要がある。
理由としては、配列の中にアクティブレコードが入っている感じなので、例え
一つしかインスタンスが取得できなかったとしても繰り返し文を使用しないとエラーとなる
例
customer.orders
<ActiveRecord::Associations::CollectionProxy [
#<Order id: 2, customer_id: 2, order_date: nil>,
#<Order id: 3, customer_id: 2, order_date: nil>,
#<Order id: 4, customer_id: 2, order_date: nil,>
]
>
※わかりやすく改行しました。
customer.orders.customer_idにすると
NoMethodError: undefined method `customer_id'というえらーになります。
これは配列になっているため取得できないんですね。
んじゃcustomer.orders[1]は取得できるんじゃないかとおもってやってみた。
<Order id: 3, customer_id: 2, order_date: nil, >
とれました。
ついでに、c.orders[1].customer_id
=> 2
とれました。
has_many :through アソシエーション
多対多関連を設けるときに用います。
これは中間テーブルを使用して、宣言するモデルと他モデルのインスタンスを0以上マッチングすることができることを示します。
条件:
has_many:中間テーブルを指定する。
has_many:中間テーブルの先のテーブル名 ,through: :中間テーブル名
※throughを指定する事で、そのテーブルを通り抜けてhas_manyで指定したテーブル にアクセスしますよーって指定だと思います。
中間テーブルへの条件:
belongs_toを使用してふたつのテーブルを指定する。
今回の例はユーザーがレーポートを書いてそのレポートに対していいねが押されるというものを多対多を使って作成してみます。
reportテーブル:レポート一覧
likeテーブル :ユーザが押したいいね一覧
ulseテーブル :ユーザ一覧
report
class Report < ActiveRecord::Base
has_many :likes
has_many :users, through: :likes
end
user
class User < ActiveRecord::Base
has_many :likes
has_many :reports, through: :likes
end
like
class Like < ActiveRecord::Base
belongs_to :parent
belongs_to :user
end
これで多対多の関係ができました。
report.likesで1レポートについたいいねの一覧がみれます。
like.reportで1いいねはどのレポートについたいいねか見れます。
user.likesで1ユーザーがつけたいいねの一覧が見れます。
ここまでが普通の多対多です。
でもいいねってどこでも使えそうです。
例えばshopに対していいねをつけるとか、コメントにたいしていいねをつけるとか。
同じ内容のテーブルをそのテーブルを増やす事なく一つのテーブルで上記のようなことを実現しようと思います。
次回ポリモーフィックに挑戦したいと思います。
「rails」from系 text_field系
form_forの場合
<%= f.text_field :name %>
生成されるタグ:<input id="user_name" type="text" name="user[name]">
→Parameters: {"utf8"=>"✓", "authenticity_token"=>"0wYmxsafQ8a0B/LrIUedQPEM5om5UNppyLDgRw4foSE=", "user"=>{"name"=>"かつ", "age"=>"13", "bar(1i)"=>"2013", "bar(2i)"=>"12", "bar(3i)"=>"7"}, "commit"=>"Create User"}
text_fieldの場合2次元配列の中に入っている。
考え方:モデルを対象として、モデルの値を受け渡すためのフォーム部品
コントローラー側で受け取る場合:user.name = params[:user][:name]
<%= text_field_tag :name %>
作成されるタグ:<input id="name" type="text" name="name">
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0wYmxsafQ8a0B/LrIUedQPEM5om5UNppyLDgRw4foSE=", "name"=>"とも", "user"=>{"age"=>"12", "bar(1i)"=>"2013", "bar(2i)"=>"12", "bar(3i)"=>"7"}, "commit"=>"Create User"}
text_field_tagの場合1次元配列の中に入っている。
考え方:モデルには関連づけず、値のみを単純に渡すフォーム部品
コントローラー側で受け取る場合:user = params[:name]
valueを明示的に入れておく方法
<%= f.text_field :name, value: "そえや" %>
展開されるHTML
<input id="user_name" type="text" value="そえや" name="user[name]">
となる。
valueにモデルに含まれるカラムを明示的に入れる方法
<%= f.text_field :name, value: @user.name %>
valueにhelperを書く方法
<%= f.text_field :name, value: helper名(@user.name) %>
idを明示的に入れておく方法
<%= f.text_field :name, id:'tenkou' %>
展開されるHTML
<input id="tenkou" type="text" name="user[name]">
「rails」f.text_fieldにhelperを書いてみるついて
今日はdate型(2013-12-06)のものをどうにかこうにか2013/12/06に直せないかと
思い色々調べた。
date型を変換するhelperがあるので、なんとかそれを使って変換させてたい!!ってのが事のほったんです。
f.text_fieldの概要
・モデルを対象として、モデルの値を受け渡すためのフォーム部品
・params 変数に二次元のハッシュとして値を渡す(一次元目のキーがモデル名)
→例:{"cic"=>{"introduction_date"=>"2013/12/16"}}
f.text_fieldの使い方
viewでの書き方
<%= form_for(@hoge) do |f| %>を使用した場合は以下のようになる。
<%= f.text_field :name %>
受け側で受け取るフォームの値は
params[:hoge][:name] となります。
通常、モデルの作成や更新に使う場合
@hoge = Hoge.new(params[:hoge])
@hoge = Hoge.find(params[:id])
@hoge.update_attributes(params[:hoge])
<%= form_tag url, options do %>
<%= text_field :hoge, :name, :value => 'default_name' %>
<%= submit_tag %>
<% end %>
という感じになります。form_tag の中で text_field という形で使うと1番目と2番目のパラメータが名前として使われ、params[:hoge][:name] に値が渡されます。 HTML としてはこんな感じで展開されます。
<input type="text" id="hoge_name" name="hoge[name]" value="default_name" />
となるそうです。
今回の実現方法
1.上記では、form_forを使用した場合、
<%= f.text_field :name %>と記載しましたが、
<%= f.text_field :name, value: name %>をする事ができます。
そのvalueの中でどうにかこうにかhelperを使用したいとおもったわけで、
書き方としては、
<%= f.text_field :introduction_date,value: format_to_date(@cic.introduction_date) , id: "datepicker", class: "form-control datepicker_cinq" %>
と記載しました。
そしたらできたので、よかったです。
「rails」コールバックについて
今回はコールバックについてわかったところまでメモ
前回おこなった、shopテーブルとcicテーブルを一発で保存するというところで、after_createを使用したのでメモ
そもそもコールバックって??
→バリデーションの実行やデータベースへの保存などのタイミングで処理を行うための機能で、あるタイミングで必ず実行する必要がある処理をコールバックに指定することで、モデルの一貫性を保つことができる機能。
今回の場合だとshopを.save(新規保存した場合)に呼び出されるのは以下。
BEGIN
1.------バリデーション------
# before_validation
# after_validation# before_save# before_create5.-- INSERT INTO "works" ...# after_create# after_save# -- COMMIT# after_commitの順番で呼び出される。
1.saveメソッドが走るとまずvalidation系を通りそれから、
2.オブジェクトが保存されるっていっている。
3.オブジェクトをモデルに登録(モデルにこんなオブジェクト保存しますよー)っていっている。
4.ここでinsertがりオブジェクトが登録される。ここまでくればinsertでこける事はないと思う。
5.オブジェクトが登録された後。
6.コミットが終了した後。
今回はafter_createを使用した。
やりたかった事がshopが登録されたときにcicも一緒に保存する。
もしshopが保存されなかった場合、cicテーブルも保存されず、ロールバックされるようにする。というのが目的です。
なので、どこでcic.saveをするかを考えました。
1.validation
→ここで、cic.saveを走らせてしまったら、shopがvalidationに引っかかる可能性が
あるため×
2.before_create
→ここではまだ、オブジェクトを作成しただけでinsert文は走っていないため×
3.createでinsert文が走るので、その後でよいと思った。なので、after_createでcic.saveを実行するのが一番よいと考えた。
4.after_createでcic.saveをすると、create文とapdate文の時に実行されるので、
shopがupdateされたときにもcic.saveが走ってしまうので、×
5.after_commitではshopがcommitされた後にcic.saveを実行するので、もしcic.saveが何らかで保存できなかったときにshopをロールバックすることが大変だとおもったため×
あってるのかなぁ・・・・
「rails」ネストしたモデルにたいして、更新する方法
前回の記事の続き
http://stomo1986.hatenablog.com/entry/2013/12/04/223545
前回まではshopに保存されたら、cicも一発で保存するというものだった。
次はapdateに手こずったので、メモ。
今回やりたい事
1.shop/show内でcicにアップデートをするためにformを設置する。
2.updateさせるのにshop内にメソッドを作成する。(update_cicというメソッド)
はまった箇所
・form_for にとび先(update_cic)を記載していたにもかかわらず、shopのupdateメソッドに飛んでしまう。
・update_cic内で、@cic = Cic.find(params[:id])で取得できるもんだと思っていたこと
・@cic = Cic.find(params[:id])後@cic.saveで保存されるものだと思っていたこと
・@cic.update(params_cic)でエラーが発生すること
知ったこと
・routesを変更すれば、hiddenタグを追加しなくていいこと。
・routesでidを指定した時のコントローラーでのfind()でのとりかたとhiddenでのfind()でのとり方が異なること。
・form_for にとび先(update_cic)を記載していたにもかかわらず、shopのupdateメソッドに飛んでしまう。の原因は以下の通り
<%= form_for(@cic, :url => {:action => 'update_cic'}, html: {class: "form-horizontal seperator", role: "form" }) do |f| %>
html
<form accept-charset="UTF-8" action="/shops/update_cic" class="form-horizontal seperator" id="edit_cic_49" method="post" role="form">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="_method" type="hidden" value="patch" />
<input name="authenticity_token" type="hidden" value="4FOyS1ellCLAkFojfnNzbufP98rYUr3FUQk2kDT8Y90=" /></div>
送られているパラメータ
"cic"=>{"introduction_date"=>"", "hp_tradesman"=>"", "consulting_contract_end_date"=>"", "collect_date"=>"", "consulting_contract_date"=>"", "consulting_contract_sum"=>"2000"}, "id"=>"update_cic"}
エラー
ActiveRecord::RecordNotFound in ShopsController#update
Couldn't find Shop with id=update_cic [WHERE (`shops`.deleted_at IS NULL)]
原因
htmlで吐き出されたタグの中に
<input name="_method" type="hidden" value="patch" />
がはいっている。updateをする際、formはpostでなければいけない。
from_forの中ではpostを宣言しているが、どうやらjavascriptでhiddenにpatchがはいっていたら、
patchを優先するというjavascriptがあるらしい。(ここは曖昧。)
次にfrom_forの中に:url => {:action => 'update_cic'},
を宣言しているにも関わらずとび先はshop/updateにpostされている。
原因は、railsの仕様で、@cicの中身は空で.newするのか、それとも
@cicの中身があるのであればupdateするというのを勝手に判断してくれている。
今回shopが生成された際にcicも一緒に保存されるようにつくっているので、cicはある。
そのため、form_forではupdateだと認識し、
:url => {:action => 'update_cic'}を無視し、shop/updateに飛ぶように変更されてしまう。
・update_cic内で、@cic = Cic.find(params[:id])で取得できるもんだと思っていたこと
次に上記を実行しないと行けないと思った背景として、
今回shopにレコードが追加されたときに、cicのレコードにはshop_idとidが入った状態で
追加される仕組みにしている。
cicレコードを更新する時にform内では、hiddenで、cic.idを指定してあげなければ、
コントローラー側で、どのレコードを更新すればいいかわからないだろう。とおもい
<%= hidden_field :cic, :id %>
を追加した。
コントローラー側では
@cic = Cic.find(params[:id])でインスタンスが作られると思っていたが、
実際の呼び出しかたは
@cic = Cic.find(params[:cic][:id])でないととれない。
りゆうとしてはパラメーターとして送られてきたのがcicのインスタンスの中のidと指定
しなければ行けなかったからだ。
・routesを変更すれば、hiddenタグを追加しなくていいこと
先ほどhiddenタグを追加してidを飛ばさないといけないと考えたが、
どうやら必要ないらしい。
form_forの中でとび先にidを付与してあげればよかった。
方法としてはルートを定義するときに、
post :update_cic, :on => :collection→/shops/update_cic
post :update_cic, :on => :member→/shops/1/update_cic
となるので、結果コントローラでは、@cic = Cic.find(params[:id])
で取得可能となる。