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

ユーザー情報と記事の紐付けしたあと保存ができない!涙「解決への道のり」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

Everything is an object-全てはオブジェクト-RubyMonkより[Ruby][和訳]

Hey guys:)
早速だけど今日も和訳をするぜ!今日の記事は残念ながらstack over flowからのものではない。
Railsの公式チュートリアルRubyの勉強できるサイトのリンクがいくつか貼ってあったので、
そこからみつけたRubyMonkっていうところから抜粋してみた。
まだオブジェクト指向に馴染めていないのでまず基本的なオブジェクトとは?のところに注目してみた。
ただし、今回訳すのは導入部分のみです。この導入部分で続きが気になったら下のリンクから続きを参照願います。

–タイトル:Everything is an object(全てはオブジェクトである)–

In Ruby, just like in real life, our world is filled with objects.

Rubyは現実世界と同様にオブジェクトで溢れている。

Everything is an object - integers, characters, text, arrays - everything.

全てはオブジェクトである。整数、文字、 文、 配列のように全てだ。

To make things happen using Ruby, one always puts oneself in the place of an object and then has conversations with other objects, telling them to do stuff.

Rubyを使うのなら機能を持たせたオブジェクトを作り、その作られたオブジェクトが他のオブジェクトに命令を与えさせるようにするんだ。

Roleplaying as an object in your program is an integral part of object-oriented programming.

自分のプログラミングでオブジェクトを機能させるのはオブジェクト指向プログラミングには欠かせないものである。

To know which object you are at the moment, one may use the keyword self.

どのオブジェクトを現在使っているか知るには、selfというキーワードを使おう。

Try it for yourself.

自分でやってみよう。

(補足)
  
[1] pry(main)> self
=> main

As you can see, if you don’t specify which object you are, you automatically play the role of the main object that Ruby provides us by default.

君がみたように、どのオブジェクトを使っているか明記しなければ自動的にmainオブジェクトを使っていることになっている。これはRubyがデフォで搭載したものだ。

どうでしょう??
これはまだオブジェクト指向について完全に説明されてないが、
記事によって説明の仕方が大分異なったりするので取っ付きやすいと思ったら下のリンクからどうぞ。

See you:)

RubyMonk - Ruby Primer - Introduction to Objects

配列の中に値が入っているか確認[和訳]

hey, guys :)
さて、今日も和訳すっか!
今回は質問者に859、回答者に1331のいいね!がついている人気の記事である。
そんなにいい質疑応答だったのか!?って気になるよね。

ーー質問ーー

I have a value ‘Dog’ and an array [‘Cat’, ‘Dog’, ‘Bird’].

訳)'Dog'という値と[‘Cat’, ‘Dog’, ‘Bird’]の配列がある。

How do I check if it exists in the array without looping through it? Is there a simple way of checking if the value exists, nothing more?

どうやったらループしないで値が配列に入っているか確認できるんだ?シンプルに確認できないか?

ーー回答ーー

You’re looking for include?:

>> ['Cat', 'Dog', 'Bird'].include? 'Dog'
=> true

訳)君が探しているのはinclude?だ。

>> ['Cat', 'Dog', 'Bird'].include? 'Dog'
=> true

–終わり–

え?これだけ?w
いいね!が多い記事は難しい話に突っ込むようなイメージがあったが、シンプルなのが意外に明白で評判いいのかもしれない。

この記事を読んだ時最初は拍子抜けだったが、あっさりすぎて次第にエンジニア初心者の私に勇気を与えてくれているような気がした。

ありがとう、user211662(質問者)とBrian Campbell(回答者)。君たちのあっさりさは人に勇気を与えた。

Thank you user211662 and Brian Campbell. Your simplenesses are giving me a hope and courage.
Hope you two will check my blog someday. God bless you.

end

原文

Check if a value exists in an array in Ruby - Stack Overflow