アソシエーション先のテーブル保存
autosave optionで設定する。
未指定ならnewは親オブジェクトの保存時に自動保存。updateは保存しない。
rails g modelやrails g controllerをする際に
ルーティングファイルも参照されるのでエラーに注意!
generateとは直接関係なくても参照されてしまうので、routes.rbを弄るのはgenerateが済んでからにしましょう。
order.limitの組み合わせ
下記のように処理を分けて書いても1回にまとまったSQL文が発行される。
このため意図しない挙動が起きる。
@datas = Product.limit(20)
@datas = @datas.order('id DESC')
↑↓で同じ結果が返る。
@datas = Product.order('id DESC').limit(20)
テーブルを切り出してからソートしたい場合にはwhereで切り出すのが吉。
order(‘count_カラム名’).count(カラム名)
自己矛盾?
.countを実行する前にcount_カラム名が使えるのはおかしい。
SQL上では先にcount関数が実行されてcount_カラム名が作られて一度中断、一連の処理が終わった後にcountの処理が再開されてハッシュを返している?
SQLのcountには集計する以上の機能がないのでハッシュにして返しているのはRails独自の機能かもしれない。なので先にcountが起動できて、別処理であるハッシュにする作業を後に行えるのかも?
.group.countと併用した場合なんかも処理が不思議な感じ。
配列の要素を数える.countメソッドなので、.groupすると配列に配列をネストしていると仮定すれば.countが使えそう。
だけどハッシュが返る道理がないので、特殊な処理が追加されいるっぽい?
mechanizeのsearchメソッド
hogehoge = agent.get(url).search("hogehoge")
fugafuga = hogehoge.search("fugafuga")
↑↓同じ結果が返る。
fugafuga = agent.get(url).search("fugafuga")
limit.orderとorder.limitで結果が同じになるケースと同じ。
おそらくRailsの内部処理で悪さしている。(2文に分けてるつもりでも合算したSQL文が発行されてる?)
値渡し と 参照渡し と 参照の値渡し
以下は自明ですよね。
def aaa(num)
num += 1
end
num = 3
aaa(num)
puts num => 3
num = aaa(num)
puts num => 4
では配列だとどうでしょうか?
def aaa(arr)
arr << 1
end
arr = []
puts arr => nil
aaa(arr)
puts arr => 1
仮引数に値を代入しただけなのに実引数が変更されるので不思議ですよね?
なんで数字は予定通りの挙動で配列だと挙動が変わるのかが謎でした。
ポイントは「参照の値渡し」
railsは基本的に値渡しです。実引数を渡しても、コピーされて仮引数が使われるためメソッド外へ影響を及ぼしません。
ですが、配列を持つ変数については配列内の実態をそのまま持つのではなく、参照先が保存されています。なので仮引数にも参照先がコピーされており、参照先を変更するような処理をすると、あたかも実引数を変更したかのように見えるのです。実引数は変更していませんが、実引数の参照先が書き換えられているのです。
多くの言語ではオブジェクトを渡すと参照の値渡しになるので、変更を明示的に返さなくても変更が反映される。
疑問
インスタンスはハッシュか?
whereやfind等で取得したインスタンスは配列で格納される。
では個々のインスタンスの中身はハッシュなのか?配列なのか?
product = Products.find(1)
product.reviews
=> [#<Review:0x00007fac8d3e4c70
id: 1,
created_at: Fri, 19 Jul 2019 05:02:46 UTC +00:00,
updated_at: Fri, 19 Jul 2019 05:02:46 UTC +00:00>,
#<Review:0x00007fac900197f0
id: 2,
created_at: Fri, 19 Jul 2019 05:03:15 UTC +00:00,
updated_at: Fri, 19 Jul 2019 05:03:15 UTC +00:00>]
配列で値が返る。[]で括られているので明示的に配列だと思う。
product.reviews[1]
=> #<Review:0x00007fac900197f0
id: 2,
nickname: "あああ",
rate: 9,
review: "skakakいいいううう\r\nえええ\r\nおおお",
product_id: 10,
created_at: Fri, 19 Jul 2019 05:03:15 UTC +00:00,
updated_at: Fri, 19 Jul 2019 05:03:15 UTC +00:00>
配列?ハッシュ?
<>の括りはハッシュの意味だろうか?
[33] pry(main)> product.reviews[1].is_a?(Hash)
=> false
[34] pry(main)> product.reviews[1].is_a?(Array)
=> false
[35] pry(main)> product.reviews[1].respond_to?(:rate)
=> true
[36] pry(main)> product.reviews[1][1]
=> nil
[37] pry(main)> product.reviews[1][:rate]
=> 9
ハッシュかどうか尋ねてもfalseが返る。
しかしシンボルでキーを指定すると値を返すのでハッシュでいいと思う。
respond_to(:key)を試すとTrue。
正確かは保証しないが、ハッシュという認識でいいと思う。
before actionで行われる処理とインスタンス変数の参照?
before_action :set_tweet
def show
@comments = @tweet.comments.includes(:user)
end
def set_tweet
@tweet = Tweet.find(params[:id])
end
これでshowメソッド内で@tweetが動くのはなぜ?
before actionの内部的な処理はどうなってるの?
showが呼ばれた時の動きとして、
set_tweet
show
の順でメソッドを呼んでいるのならset_tweet内で定義した@tweetは次のメソッドで利用できない。
def show
set_tweet
@comments = @tweet.comments.includes(:user)
end
みたいに書き換えているとしても結局変数を呼べないよね?
少なくともrubyの記法ならこんな書き方しても機能しないはず。
理解
そもそも”@”tweetと書くということは、これはただの変数ではなくインスタンス変数。
では@tweetを属性に持つインスタンスとは何か?
おそらくコントローラークラスのインスタンスである。
つまりこの例で言うと、Tweetsクラスのインスタンス(hogehoge)が属性として@tweetを持っている。
なので他のメソッド(インスタンスメソッド)を利用しても共通してインスタンス(hogehoge)の属性を扱うことができる。
おそらくrailsでは、コントローラが呼び出される際に自動的にコントローラクラスのインスタンスが生成される。
このインスタンスに対して、コントローラ内のインスタンスメソッドで処理を行い、インスタンス変数を格納していく。
ビューで使う場合にもこのインスタンスが引き渡されているはずなので、html.erb内で@付きの変数(インスタンス変数)を利用できる。
いくつかのサイトをみてみたが、大筋の理解は間違ってなさそう。
ただし、@付きの変数に関してはインスタンス変数だから、ではなくこれを目印として別途viewへ引き渡すための監視を特別に行なっている模様。
部分テンプレート?
投稿時と編集時で同じフォームを使いまわそうとした際に、下記のようにしても動く。
変数を渡していないのにフォーム上にeditしたい値が埋まった状態で表示されるのはなぜ???
edit.html.erb
<%= render partial: "form"%>
コントローラ
def edit
@post = Post.find(params[:id])
end
_form.html.erb
<%= form_for(@post, html:{class: "col s12"}) do |f| %>
<div class="input-field col s12">
<%= f.text_area :text, autocomplete: "text" %>
<%= f.label :text , for: "textarea1"%>
</div>
<% end %>
フォーム用のような単一のインスタンスの場合、変数に保存されている情報がそのまま使えるため、わざわざrenderに引き渡さなくてもOKな感じ?
通常はrenderする場合はcollection等でバラして使うので、わざわざlocalを書いているものと思われる。
deviseのuser controllerはどうすべき?
users controllerはrails g controller usersで作るのが正しいのか?
userモデルに対してuser controllerとdevise controllerの2つが管理することになって、気持ち悪いんだけど普通なんでしょうか?
user#showとかを使うためにrails g controller userしているケースが結構見られる。
params.require
わざわざrequireメソッドを使っているが、ハッシュなので普通に取り出しても動く。
params.require(:review)
params[:review]
なのでparamsに対して.require().permit()とする理由は可読性だけ?
.new(class)に外部キーっぽい配列を引き渡した場合の処理
has_many throughでuserとgroupモデルが繋がっているときに
def create
@group = Group.new(create_params)
@group.save
end
private
def create_params
params.require(:group).permit(:name, user_ids: [])
end
“user_ids”=>[“”, “1”, “2”]を引き渡したところ、
@group
=> #<Group:0x00007ffb6f749268 id: nil, name: "sgggg", created_at: nil, updated_at: nil>
@group.users
=> [#<User id: 1, email: "aaa@aaa", name: "hogehoge">,
#<User id: 2, email: "fdg@dfg", name: "fugafufa">]
が返った。.newに配列を渡すと複数生成されるのか?
そもそも配列を渡してよいのか?
initializeメソッドでの処理だと思うが、その実態はどのように確認したらよいのか?
コメント