読者です 読者をやめる 読者になる 読者になる

rails内のクラスで実行されているこれって一体何だ!?[和訳]

Hey guys :)
今日も和訳するぜ!
stack overflowでrails初心者に興味深い記事があったので紹介します!
まだ私の知識は浅いのできつい和訳になっているので、できれば和訳を参考に英文を読んでいただければと思います汗

–質問–

I have just started learning ruby on rails and I have encountered code like below:

Ruby on Railsを始めたばかりなんだけど、下記のようなコードに出会った。

class Post < ActiveRecord::Base
 validates_presence_of   :title
 belongs_to :user
end

There are two method calls inside the class body. I have had a hard time finding any ruby documentation that describes how method calls from within a body of a class (but outside of any method) work.

クラス内で2つのメソッドが呼び出しをしている。どうやってメソッドが呼び出しをしているのかRubyのドキュメントを必死に探してもみつからない。

All the books I have, only describe how to define class and instance methods and how to call them from within other methods.

私が持っている本には全てどのようにクラスやインスタンスメソッドを作って、どうやって他のメソッドから呼び出せるのかしか説明されていないんだ。

The questions I have are: How and when are these methods called? How are they defined? Are they mixins defined in some active record module?

私の質問は..いつどのようにこれらのメソッドは呼び出されるのか。どのように定義されているのか。ActiveRecord的なものの中で定義されているのか?

–回答–

The body of a class definition is an execution context for code just like any other.

クラスの定義の主要部分としてはコードを実行することができるということである。

Code there is executed within the context of the class (meaning self is the class object, which is an instance of Class).

クラス内のコードが実行されている。(selfはインスタンスクラスであるクラスオブジェクトという意味)

You can have locals and instance variables (which will belong to the class object itself rather than instances of the class) and you can call any method that class object responds to.

インスタンスクラスよりもクラスオブジェクトに付随している)ローカル、インスタンス変数を持つことが出来、クラスオブジェクトが対応するメソッドを呼び出すことが出来る。

The code is run once the class definition block is finished.

コードはクラスで定義されたブロックを通過すると実行される。

In this case, ActiveRecord::Base defines the class methods validates_presence_of and belongs_to.

今回のケースだと、ActiveRecord::Baseがvalidates_presence_ofとbelongs_toのクラスメソッドを定義しているのだ。

ActiveRecord内で定義したものを実行した結果は以下である(例として)。

[11] pry(main)> ActiveRecord::Base.belongs_to(:blog_post)
=> {"blog_post"=>
  #<ActiveRecord::Reflection::BelongsToReflection:0x007fa3ee03c958
   @active_record=ActiveRecord::Base,
   @association_scope_cache={},
   @automatic_inverse_of=nil,
   @constructable=true,
   @foreign_type="blog_post_type",
   @klass=nil,
   @name=:blog_post,
   @options={},
   @plural_name="blog_posts",
   @scope=nil,
   @scope_lock=#<Mutex:0x007fa3ee03c570>,
   @type=nil>}

追記)contextを上手く訳するのが難しかったので省略しましたw

see you!!:)  

リンク

Ruby Method calls declared in class body - Stack Overflow

railsのform_forをstylingする[和訳]

hey guys :)
form_forをhtml内でstylingできるんだね!
stack overflowからの豆知識を共有してみる。

–質問–

Is there a way to add styling to rails form_for and make it display inline?

railsform_forで stylingしてdisplayをinlineに出来たりするの?

–回答–

There might be a cleaner way to do this, but it works. (I tried with another nested hash, no dice)
単純かもしれないが、こうすれば出来るよ。(他のネストされたハッシュでも試してみたけど、無意味だった)

 <% form_for(@model, :html => { :style => 'background-color:red;' }) do |f| %>

inlineについては触れられてないじゃん!汗
まぁ、記事内のコメントに「なぜinlineにしたいんだい?」って的確なツッコミがあるのは頷けるw

see you !!:)

リンク

html - rails form_for styling - Stack Overflow

ユーザー情報と記事の紐付けしたあと保存ができない!涙「解決への道のり」Ruby on Rails

Hey guys!!
ユーザー情報と記事の紐付け後につまった!!
今思えばなぜあんなことをしてしまっていたのか。。

ログイン機能が搭載されているgem Deviseを取り入れて、ArticleのDBにuser_idを追加したことを前提に話をすすめる。
ちなみにrails5を使用しています。

それぞれのmodelにhas_manybelongs_to で紐付けした。

models/user.rb

class User < ApplicationRecord 

  has_many :articles
  
  validates :name, presence: true
  validates :email, presence: true, uniqueness: true
  devise :database_authenticatable, :registerable,
              :recoverable, :rememberable, :trackable, :validatable,
              :omniauthable
end

models/article.rb

class Article < ApplicationRecord 

  belongs_to :user

  validates :title, presence: true
  validates :content, presence: true, length: { maximum: 140 } 
  validates :user_id, presence: true
end

これは特に問題なさそうだ。

そして今回の問題がcontrollerのcreateアクションの部分だ。

class ArticlesController < ApplicationController
  
  def create
    @article = Article.new
    @article.title = params[:article][:title]
    @article.content = params[:article][:content]
    @article.save
    redirect_to root_path
  end

試しに記事を投稿してみよう…

..!?

更新したようにみえたけど、DBに保存されていない…

saveをした時にデータがちゃんとあるか確認するために @article.saveの直後にraise @article.inspectを記述して記事を更新。
もちろんRuntime Errorがブラウザ上表示されるがその中身をみるとuser_idとidがnilだ。

rails consoleで確認。

$ @article = Article.new
$ @article.title = "title-test"
$ @article.content = "content-test"
$ @article.save

=> false  

なるほど。 idが足りないからなのか? 検証してみよう。

$ @article = Article.new
$ @article.title = "title-test"
$ @article.content = "content-test"
$ @article.id = 1
$ @article.save

=> false  

ふむふむ。user_idで検証してみよう。

$ @article = Article.new
$ @article.title = "title-test"
$ @article.content = "content-test"
$ @article.user_id = 1
$ @article.save

=> true

お!user_idがあればsaveできるんだな!! user_idをcurrent_userヘルパーメソッド(Deviseにデフォで搭載)とイコールにすれば保存ができそう。

class ArticlesController < ApplicationController

 before_action :authenticate_user!    #追加(これを記述しないとcurrent_userが使えない!!)
  
  def create
    @article = Article.new
    @article.user_id = current_user  #追加
    @article.title = params[:article][:title]
    @article.content = params[:article][:content]
    @article.save
    redirect_to root_path
  end

よし、これで上手くいくはずだ。記事を投稿してみよう。

…えーーー、なんで保存されてないんだーーー涙涙

stack overflowで"rails can’t save data"みたいな感じで検索し、でてきた記事がこれ

ruby - Troubleshooting: Rails can't save to database in production? - Stack Overflow

save!っていうメソッドを使ってみたらどうだろうか?とのこと。
何か手がかりが掴めそうだ

よし、やってみっか!

class ArticlesController < ApplicationController

 before_action :authenticate_user!   
  
  def create
    @article = Article.new
    @article.user_id = current_user  
    @article.title = params[:article][:title]
    @article.content = params[:article][:content]
    @article.save!   #変更
    redirect_to root_path
  end

おやおや?

Validation failed: User must exist, User can’t be blank ってブラウザで言われた。

ははーん、答えがみえてきたぞ。
念のために"Validation failed: User must exist, User can’t be blank"をコピペでググったらstack overflowに行き着いた。

ruby on rails - Validation failed: User can't be blank - Stack Overflow

はい、やっぱり上記の記事と答えが一緒でした!

class ArticlesController < ApplicationController

 before_action :authenticate_user!   
  
  def create
    @article = Article.new
    @article.user = current_user   #変更  
    @article.title = params[:article][:title]
    @article.content = params[:article][:content]
    @article.save
    redirect_to root_path
  end

これでやっと記事が保存できた!!

今回の反省点は二つあった。
一つ目はuser_idがnilだったので保存ができなかったという考えに取り憑かれてuser_idに絞って考えてしまっていたこと。
もう少し視野を広げていたら、そもそもuserがないって早く気付いていたかもしれなかったですね。汗汗

そして二つ目はstack overflowの記事でポイントが低いものはあてにならないと思いスルーしていたことである。
上記で取り上げた2つの記事は両方共ポイントが少なかったが解決に導いてくれた。
ポイントが多い記事がないかついつい探してしまいがちだが、初心者の私にとってはポイントが低い記事も知識の宝庫であることに気付かされた。
これからはポイント数をあまり気にせずに、stack overflowを活用していきたいと思います。。

see you!!

redirect_toになんでインスタンス変数??

Hey guys!!:)
今日もstackoverflowの記事を訳すよー。今回は2013年に投稿した古い記事だけど、初心者の勉強の為には良記事だなと思ってピックアップした。

–質問–

I am confused about passing an instance variable to a redirect_to method. How is this possible? I thought redirect_to would be relevant for redirecting to another webpage or a url.

redirect_toメソッドにインスタンス変数を受け渡していることについて混乱している。なんでこんなことが出来るの?私はredirect_toは他のウェブページやURLを表示させることと関係するのだと思ってたよ。

In the examples given on the guide it says the following:
あるガイドが下記のような例でこんなこと説明していたんだ;

2.2.2 Rendering an Action’s View

If you want to render the view that corresponds to a different action within the same template, you can use render with the name of the view:
もし同じテンプレートで違うアクションを実行させたかったら、renderにviewの名前を渡して使えるよ。  
  
def update
  @book = Book.find(params[:id])
  if @book.update_attributes(params[:book])
    redirect_to(@book)
  else
    render "edit"
  end
end

The render “edit” makes complete sense, its going to render that new form again.

render editは確かに理に適っていて、新しいフォームを再度表示させる。

But what in the world is going on with redirect_to(@book)?

でもredirect_to(@book)って一体何なんだ?

What exactly is that going to render and how is a book object going to be redirected to?

具体的にrenderは何をして、bookオブジェクトはどのようにしてリダイレクトしているんだ?

BTW, the book model has columns, Name, author, pages etc…

追記すると、bookモデルはカラム、名前、作者、ページ等がある。

–回答–

redirect_to(options = {}, response_status = {}) Redirects the browser to the target specified in options.   
  
redirect_to(options = {}, response_status = {})ブラウザをオプションで指定した所にリダイレクトする。
  
Record - The URL will be generated by calling url_for with the options, which will reference a named URL for that record.  
  
レコード - URLはオプションでurl_forを呼びだすことによって生成される。そのレコードより名付けられたURLを参照する。

So when one does redirect_to(@book) @book is a specific record with an id .

なのでredirect_to(@book)を実行した時、@bookはidのもつ特定のレコードだ。

Thus, the associated records (in this case @book) show method is used as a template.

したがって、関連のレコード(このケースでは@book)があるshowメソッドはテンプレートに使われる。

In addition to above, if you look at the routes.rb file which defines these paths you will notice

上記に加えてもしroutes.rbファイルをみてみたら、下記のようなパスが定義されていて何か気づくだろう。

resources :books

Now this route is essentially translated as (you can see by running rake routes)

このルートは下記のように読み込まれる(rake routesを実行すればみれるよ)。

    books GET    /books(.:format)                   books#index
          POST   /books(.:format)                   books#create
 new_book GET    /books/new(.:format)               books#new
edit_book GET    /books/:id/edit(.:format)          books#edit
     book GET    /books/:id(.:format)               books#show
          PUT    /books/:id(.:format)               books#update
          DELETE /books/:id(.:format)               books#destroy  

Notice the book GET /books/:id books#show - which gets matched when you do redirect_to(@book)

book GET/books/:id books#showで何か気づくかな?これはredirect_to(@book)と結びついているんだ。

終わり  

どうだったかな?たしかにインスタンス変数を引数にしているのには違和感があった。
この記事を読んで少し霧が晴れたような気がしたかな!

see you!!

リンク

ruby - Confusion about passing instance variables to redirect_to method. As seen in Rails Guides - Stack Overflow

deviseのカラム追加-Ruby on Rails-

Hey, guys:)
最近Deviseっていうgemを使ってログイン機能を開発中のアプリに追加させた。めっちゃ便利でやれることも盛り沢山!

しかし!!

なぜユーザーの名前を登録できるカラムがないのだ!!デフォルトで搭載されているはずじゃ…

もやもやしながらもnameを追加させたのでここで共有してみる。

バージョンはRails 5 向けです。

まずは皆さんお馴染みのmigrationから

$ bin/rails g migration AddNameToUsers name:string

それでもちろんrakeだね

$ rake db:migrate

はい、追加出来たね!

しかし!これだけでは終われない!!

新規ユーザー登録画面でユーザー名を登録できるようにする。

ファイル:app/views/devise/registrations/new.html.erb

<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <div class = "field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>   #この4行だけ追加、それ以外はデフォルトで書かれてるので以下省略

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true %>
                          :
                          :

この時、デフォのコードを真似してf.name_field :nameみたいな調子乗った記述をしないように!(実体験。自らドブにハマりました..)

次のコードを追加するの忘れずに!!

ファイル;app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?  
  
  protected

  def configure_permitted_parameters
    added_attrs = [:name, :email, :password, :password_confirmation, :remember_me]
    devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
    devise_parameter_sanitizer.permit :account_update, keys: added_attrs
  end
end

以上!!

Railsのバージョンが違うと最後のapplication_controller.rbに書く記述が変わってくるので注意してください。

See ya!!

nil?, empty?とblank?の違い-Ruby on Rails-[和訳]

hey, guys:)
nilとemptyとblankって一緒じゃないの?とふと疑問に思ってstack overflowで検索。。
なるほど〜,と思う説明があったので和訳してみる。この記事は質問者に770,回答者に1054のいいねがついているので良記事に違いない。
それでは和訳してみる。

–質問–

I find myself repeatedly looking for a clear definition of the differences of nil?, blank?, and empty? in Ruby on Rails.

私は何回もRuby on Railsnil?,blank?とempty?について明白な定義がないか探している。

–回答–

.nil? can be used on any object and is true if the object is nil.

.nil?はどんなオブジェクトに使えて、オブジェクトがnilならtrueを返す。

.empty? can be used on strings, arrays and hashes and returns true if:

.empty?は文字列(string)、配列(array)やハッシュ(hash)に使えて、例えば次のような時はtrueを返す;

String length == 0  
Array length == 0
Hash length == 0  

Running .empty? on something that is nil will throw a NoMethodError.

何かnilのものに.empty?をを使うとNoMethodErrorになってしまう。

That is where .blank? comes in.

その場合はblank?が使われるところだ。

It is implemented by Rails and will operate on any object as well as work like .empty? on strings, arrays and hashes.

.empty?が文字列、配列やハッシュで使われるのと同じようにRailsで実装できる。

nil.blank? == true
false.blank? == true
[].blank? == true
{}.blank? == true
"".blank? == true
5.blank? == false
0.blank? == false

.blank? also evaluates true on strings which are non-empty but contain only whitespace:

.blank?は空白スペースの文字列にtrueを返す:

"  ".blank? == true
"  ".empty? == false

Rails also provides .present?, which returns the negation of .blank?.

Rails.blank?の否定を返す.present?を用意している。

Array gotcha: blank? will return false even if all elements of an array are blank.

.blank?は配列のすべての要素が空の場合であってもfalseを返す。

To determine blankness in this case, use all? with blank?, for example:

この場合、空か判断するにはall?blank?を一緒に使おう、例えば:

[ nil, '' ].blank? == false
[ nil, '' ].all? &:blank? == true 

これは覚えなきゃいけないのかな? 使う時にわからなくなったらまたこの記事をみるとしよう!
この記事のリンクに素敵な表があったからよかったらチェックしてみてね!
see you!!

A concise explanation of nil v. empty v. blank in Ruby on Rails - Stack Overflow

コントローラー名とモデル名の変更手順-Ruby on rails-

Hi:) When it’t time to blog, I translate and learn.
ということで今日もStack over flowの記事から抜粋。
記事表題は「How to rename rails controller and model in a project
(railsのプロジェクトでとうやったらコントローラ名とモデル名を変更するのか)」
です。
それでは記事を翻訳してみよう。

質問

I would like to rename a controller and the associated model:

コントローラー名と関連するモデル名を変更したい。

I wanted to change the Corps controller to Stores and the same (without final s) for the model.

CorpsコントローラーをStoresコントローラーに変えたく、モデルも(語尾のsを省いて)同様に名前を変えたいんだ。

Looking on google, people suggested to destroy and then generate again the controller and model. The problem is that it will erase the actual code of each files!

ググってみたが、一度消してからまたコントローラーとモデル作るように提案されたんだ。
けれども、記述したコードを消したくないんだ!

Any solution?

何か解決策はあるかな?

回答

Here is what I would do:

私のやりかたはこれだ;

Create a migration to change the table name (database level). I assume your old table is called corps. The migration content will be:

テーブル名(データベースも)を変更する為にmigrationを作る。君の古いテーブル名はcorpsだろう。
migrationの中身はこうであろう。

class RenameCorpsToStores < ActiveRecord::Migration
  def change
    rename_table :corps, :stores
  end
end

Change your model file name, your model class definition and the model associations:

モデル名とクラス名とモデルに関連付けされるものを変更しよう。

File rename: corp.rb -> store.rb  
  
# ファイル名変更:corp.rb -> store.rb  
  
Code of store.rb: Change class Corp for class Store  
  
# store.rb内のclass Corpをclass Storeに  
  
Rename all the model associations like has_many :corps -> has_many :stores  
  
# モデルに関連したものを全て変更。例えばhas_many:corps -> has_many:stores

Change your controller file name and your controller class definition:

コントローラーのファイル名とクラス名を変更しよう。

File rename: corps_controller.rb -> stores_controller.rb  
  
# ファイル名変更 : corps_controller.rb -> stores_controller.rb  
  
Code of stores_controller.rb: Change class CorpsController for class StoresController  
  
# stores_controller.rb内のclass CorpsControllerをclass StoresControllerに  
  
Rename views folders. From corps to stores.  
  
# ビューのフォルダ名もcorpsからstoresに変更

Make the necessary changes in paths in the config/routes.rb file, like resources :corps -> resources :stores, and make sure all the references in the code change from corps to stores (corps_path, …)

config/routes.rb内の必要なパス名を変更する。例えばresources :corpsresources :storesに。
corpsをstoresに変えたか注意深く確認しよう。(corps_path,…)

Remember to run the migration :)

migrationを実行するのを忘れないでね:)

If previous is not possible, try to delete the db/schema.rb and execute:

もし上記のやり方で上手く行かなかったら、db/schema.rbを削除して次を実行しよう。

 $rake db:drop && rake db:create && rake db:migrate

終    

かなり無難なやり方って感じw
でもこの回答に118のいいねが付いているので結構な賛同を得ているやり方のようだ。
私も実際にこれやってみて、vim:%s/corps/stores/gみたいにやればあっさりcontroller名とmodel名を変えることができた。

See you!!

リンク How to rename rails controller and model in a project - Stack Overflow