- 投稿日:2020-08-07T23:37:13+09:00
[Rails][Gem] mini_racer_extension.so: undefined symbol: _ZTTNSt7* 解決法
起こったこと
Vagrant
CentOS
7 環境に Rails プロジェクトに gemreact_on_rails
を導入して
React を動かそうとしたところrails generate react_on_rails:install
で追加されていた依存する gem
mini_racer
が以下のエラーを出してRails 起動しなくなった。/home/vagrant/dev/rails-proj/vendor/bundle/ruby/2.6.0/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/ kernel_require.rb:23:in `require': /home/vagrant/dev/rails-proj/vendor/bundle/ruby/2.6.0/gems/mini_racer-0.3.1/lib/ mini_racer_extension.so: undefined symbol: _ZTTNSt7__cxx1119basic_istringstreamIcSt11char_traitsIcESaIcEEE - /home/vagrant/dev/rails-proj/vendor/bundle/ruby/2.6.0/gems/mini_racer-0.3.1/lib/mini_racer_extension.so (LoadError)原因
最近、gem
mini_racer
が version 0.3.x に上がったようで
不安定のよう。解決法
とりあえず、gem
mini_racer
(最近0.3.xに上がったようなので) 、修正対応のある、最新のversion を取り入れる。Gemfilegem 'mini_racer', git: 'https://github.com/rubyjs/mini_racer', platforms: :ruby該当部分
https://github.com/rubyjs/mini_racer/commit/94cdb03211044f2e0620c6275525d09f84f26c78
補足
最初は gem
mini_racer
を 安定版の0.2.15
に戻したりしたが、
libv8
などで特定のGCC version 依存があるようで、
OSの GCC version調整がいるようで、
とりあえずこれで。$ gcc --version gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)https://www.cyberciti.biz/faq/centos-rhel-7-redhat-linux-install-gcc-compiler-development-tools/
https://stackoverflow.com/questions/36327805/how-to-install-gcc-5-3-with-yum-on-centos-7-2
参考
https://stackoverflow.com/questions/36327805/how-to-install-gcc-5-3-with-yum-on-centos-7-2
- 投稿日:2020-08-07T23:07:55+09:00
any?メソッドを使用してエラーメッセージの取得
エラーメッセージの表示の際に使用したメソッドをまとめたいと思います。
any?メソッドとは
any?メソッドはすべての要素が偽である場合に false を返します。真である要素があれば、ただちに true を返します。
書き方はこのような感じ
p [false, nil].any? # => false例えばエラーメッセージの記述を部分テンプレートに記載してオブジェクトにエラー情報がある場合のみ表示するように設定するとします。
app/controllers/items_controller.rbdef create @item = Item.new(item_params) if @item.save redirect_to root_path else render :new end endこの記述でバリデーション等で保存に失敗した際に
newアクションへ戻るように設定します。app/views/items/new.html.erb<%= form_with model: @item, local: true do |f| %> <%= render 'shared/error_messages', model: @item %>レンダー先にエラーの情報を持ったモデルオブジェクトを持っていきます。
app/views/shared/_error_messages.html.erb<% if model.errors.any? %> <div class="error-alert"> <ul> <% model.errors.full_messages.each do |message| %> <li class='error-message'><%= message %></li> <% end %> </ul> </div> <% end %>any?メソッドでerrorsの中身を確認して存在する場合はtrueとなりエラーの繰り返し処理が働きます。
またpresent?メソッドとかなり似ていますがany?メソッドは
上記例では繰り返し処理でエラーメッセージ を表示していますが
labelの場所ごとにエラーメッセージを表示したい場合はinclude?メソッドを使ってもいいなと思います。
- 投稿日:2020-08-07T19:16:54+09:00
【Rails】form_withを完全に理解した
この記事の内容
- form_withメソッドの使い分け
- それに伴うストロングパラメータの取り扱い
- フォーム内容をHTTP通信させる方法
環境
$ rails -v Rails 6.0.3.1$ ruby -v ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19]form_withとは
フォーム送信するためのUI部品をビルドするメソッドで、自動でサーバー側のコントローラアクションを切り替えてくれる特徴を持つ。
切り替える要因となるのは、オプションのmodelやurlに対する値によって変わり、以下のようになる。
オプション @userの中身 呼び出されるアクション 用途 model: @user User.new create ユーザー作成 model: @user User.find() update ユーザー編集 url: sessions_path create ユーザーログイン また、オプションの違いを比較すると、以下のようになる。
オプション 入力エリアのname属性 ストロングパラメータ model: @user name="user[email]" params.require(:user).permit(:email) url: users_path name="email" params.permit(:email) modelオプションを使った例
<%= form_with model: @user do |f| %> <%= f.label :name, "名前" %> <%= f.text_field :name, placeholder: "山田" %> <%= f.submit "登録する" %> <% end %>urlオプションを使った例
<%= form_with url: sessions_path do |f| %> <%= f.label :name, "名前" %> <%= f.text_field :name, placeholder: "山田" %> <%= f.submit "ログインする" %> <% end %>localオプション
実は、デフォルトで
remote: true
オプションが付与されており、いわゆるAjax通信をするようにあらかじめ設定されている。
そのため、特に何も設定しないと、renderメソッドが行われないことによるflashが表示されなかったりする。通常のHTTP通信を行うために、以下のような設定を行うことで、上記の問題を解決することができる。
<%= form_with model: @user, local: true do |form| %>まとめ
form_withは、自動でHTTPリクエストの種類を判別してくれるので、便利。
- 投稿日:2020-08-07T18:54:01+09:00
Secretsantasができるまで
事前準備
- secretsantasという名のフォルダを作成し、VS codeで開く
- rails 5.0.7.2 new secretsantas -d mysql
- cd secretsantas
- rails db:create
- Githubに連携
- public/uploads/*を.gitignorenに追加
- http://localhost:3000/にアクセスしデフォルト画面を表示
- 投稿日:2020-08-07T18:54:01+09:00
Secretsantasができるまで コーディング
事前準備
- secretsantasという名のフォルダを作成し、VS codeで開く
- rails 5.0.7.2 new secretsantas -d mysql
- cd secretsantas
- rails db:create
- Githubに連携
- public/uploads/*を.gitignorenに追加
- http://localhost:3000/にアクセスしデフォルト画面を表示
user登録(ウィザード方式)
1.
Gemfilegem 'devise'2.
$ rails g devise:install3.
config/routes.rbRails.application.routes.draw do root to: "home#index" end4.
$ rails g controller home5.
app/views/home/index.html.erb<h1>トップページ</h1>6.
rails g devise usermigrationfile# frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| ## Database authenticatable t.string :nickname, null: false t.string :email, null: false, default: "", unique: true t.string :encrypted_password, null: false, default: "" t.string :first_name, null: false t.string :last_name, null: false t.string :first_name_kana, null: false t.string :last_name_kana, null: false t.date :birthday, null: false t.boolean :is_deleted, null: false, default:false ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable # t.string :confirmation_token # t.datetime :confirmed_at # t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end8.$ rails db:migrate
9.
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname,:first_name,:last_name, :first_name_kana, :last_name_kana,:birthday,:image]) end end10.
app/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable validates :nickname,:first_name,:last_name, :first_name_kana, :last_name_kana,:birthday,:image ,presence: true end11.$ rails g devise:views
12.
app/views/devise/registrations/new.html.erb<h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :nickname %><br /> <%= f.text_field :nickname %> </div> <div class="field"> <%= f.label :first_name %><br /> <%= f.text_field :first_name %> </div> <div class="field"> <%= f.label :last_name %><br /> <%= f.text_field :last_name %> </div> <div class="field"> <%= f.label :first_name_kana %><br /> <%= f.text_field :first_name_kana %> </div> <div class="field"> <%= f.label :last_name_kana %><br /> <%= f.text_field :last_name_kana %> </div> <div class="field"> <%= f.label :birthday %><br /> <%= f.date_field :birthday %> </div> <div class="field"> <%= f.label :image %><br /> <%= f.text_field :image %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>app/views/home/index.html.erb<h1>トップページ</h1> <% if user_signed_in?%> <h2>ログインしています</h2> <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> <% else %> <h2>ログインしていません</h2> <%= link_to "新規登録", new_user_registration_path %> <%= link_to "ログイン", new_user_session_path %> <% end %>13.挙動を確認
ログインできるか
- 投稿日:2020-08-07T18:54:01+09:00
Secretsantasができるまで 事前準備〜ユーザ新規登録(ウィザード方式)
事前準備
- secretsantasという名のフォルダを作成し、VS codeで開く
- rails 5.0.7.2 new secretsantas -d mysql
- cd secretsantas
- rails db:create
- Githubに連携
- public/uploads/*を.gitignorenに追加
- http://localhost:3000/にアクセスしデフォルト画面を表示
user登録(ウィザード方式)
deviseを準備
Gemfileにdeviseを記述し、bundle install
Gemfilegem 'devise'アプリケーション内でdeviseのヘルパーメソッドなど使用するために以下のコマンドを叩く
$ rails g devise:installトップページを作成
config/routes.rbRails.application.routes.draw do root to: "home#index" endhomeコントローラを作成
$ rails g controller home******下
app/views/home/index.html.erb<h1>トップページが表示される</h1>ログインできるか確認
rails g devise userdb/migrate/20XXXXXX.rb# frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| ## Database authenticatable t.string :nickname, null: false t.string :first_name, null: false t.string :last_name, null: false t.string :first_name_kana, null: false t.string :last_name_kana, null: false t.date :birthday, null: false t.text :image, null: false t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable # t.string :confirmation_token # t.datetime :confirmed_at # t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :nickname, unique: true add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end$ rails db:migrateSequel Proでテーブルが作成されているか確認
次に、Appilication Controllerを修正します。nameやageなどのカラムを追加したためです。
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname,:first_name,:last_name, :first_name_kana, :last_name_kana,:birthday,:image]) end endカラムのバリデーションを設定
app/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable validates :nickname,:first_name,:last_name, :first_name_kana, :last_name_kana,:birthday,:image ,presence: true endビューをカスタマイズ
$ rails g devise:viewsapp/views/devise/registrations/new.html.erb<h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :nickname %><br /> <%= f.text_field :nickname %> </div> <div class="field"> <%= f.label :first_name %><br /> <%= f.text_field :first_name %> </div> <div class="field"> <%= f.label :last_name %><br /> <%= f.text_field :last_name %> </div> <div class="field"> <%= f.label :first_name_kana %><br /> <%= f.text_field :first_name_kana %> </div> <div class="field"> <%= f.label :last_name_kana %><br /> <%= f.text_field :last_name_kana %> </div> <div class="field"> <%= f.label :birthday %><br /> <%= f.date_field :birthday %> </div> <div class="field"> <%= f.label :image %><br /> <%= f.text_field :image %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Sign Up" %> </div> <% end %> <%= render "devise/shared/links" %>app/views/home/index.html.erb<h1>トップページ</h1> <% if user_signed_in?%> <h2>ログインしています</h2> <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> <% else %> <h2>ログインしていません</h2> <%= link_to "新規登録", new_user_registration_path %> <%= link_to "ログイン", new_user_session_path %> <% end %>新規登録できるか確認
deviseをカスタマイズしてウィザード形式の新規登録にする
$ rails g model addressdb/migrate/20XXXXX.rbclass CreateAddresses < ActiveRecord::Migration[5.0] def change create_table :addresses do |t| t.integer :zipcode, null: false t.string :prefecture, null: false t.string :city, null: false t.string :district, null: false t.string :building t.string :room t.references :user, foreign_key: true t.timestamps end end end$ rails db:migrateapp/models/address.rbclass Address < ApplicationRecord belongs_to :user, optional: true validates :zipcode, :prefecture, :city,:district,presence: true endapp/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable validates :nickname,:first_name,:last_name, :first_name_kana, :last_name_kana,:birthday,:image ,presence: true has_one :address end$ rails g devise:controllers usersconfig/routes.rbRails.application.routes.draw do devise_for :users, controllers: { registrations: 'users/registrations', } root to: "home#index" endapp/controllers/users/registrations_controller.rb# frozen_string_literal: true class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] def new @user = User.new end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_up_params # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) # end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end endapp/views/devise/registrations/new.html.erb<h2>ユーザー情報登録</h2> <%= form_for(@user, url: user_registration_path) do |f| %> <%= render "devise/shared/error_messages", resource: @user %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :nickname %><br /> <%= f.text_field :nickname %> </div> <div class="field"> <%= f.label :first_name %><br /> <%= f.text_field :first_name %> </div> <div class="field"> <%= f.label :last_name %><br /> <%= f.text_field :last_name %> </div> <div class="field"> <%= f.label :first_name_kana %><br /> <%= f.text_field :first_name_kana %> </div> <div class="field"> <%= f.label :last_name_kana %><br /> <%= f.text_field :last_name_kana %> </div> <div class="field"> <%= f.label :birthday %><br /> <%= f.date_field :birthday %> </div> <div class="field"> <%= f.label :image %><br /> <%= f.text_field :image %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Next" %> </div> <% end %> <%= render "devise/shared/links" %>app/controllers/users/registrations_controller.rb# frozen_string_literal: true class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] def new @user = User.new end def create @user = User.new(sign_up_params) unless @user.valid? flash.now[:alert] = @user.errors.full_messages render :new and return end session["devise.regist_data"] = {user: @user.attributes} session["devise.regist_data"][:user]["password"] = params[:user][:password] @address = @user.build_address render :new_address end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_up_params # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) # end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end endconfig/routes.rbRails.application.routes.draw do devise_for :users, controllers: { registrations: 'users/registrations' } devise_scope :user do get 'addresses', to: 'users/registrations#new_address' post 'addresses', to: 'users/registrations#create_address' end root to: "home#index" endapp/views/devise/registrations/new_address.html.erb<h2>住所情報登録</h2> <%= form_for @address do |f| %> <%= render "devise/shared/error_messages", resource: @address %> <div class="field"> <%= f.label :zipcode %><br /> <%= f.text_field :zipcode %> </div> <div class="field"> <%= f.label :prefecture %><br /> <%= f.text_field :prefecture %> </div> <div class="field"> <%= f.label :city %><br /> <%= f.text_field :city %> </div> <div class="field"> <%= f.label :district %><br /> <%= f.text_field :district %> </div> <div class="field"> <%= f.label :building %><br /> <%= f.text_field :building %> </div> <div class="field"> <%= f.label :room %><br /> <%= f.text_field :room %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>app/controllers/users/registrations_controller.rb# frozen_string_literal: true class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] def new @user = User.new end def create @user = User.new(sign_up_params) unless @user.valid? flash.now[:alert] = @user.errors.full_messages render :new and return end session["devise.regist_data"] = {user: @user.attributes} session["devise.regist_data"][:user]["password"] = params[:user][:password] @address = @user.build_address render :new_address end def create_address @user = User.new(session["devise.regist_data"]["user"]) @address = Address.new(address_params) unless @address.valid? flash.now[:alert] = @address.errors.full_messages render :new_address and return end @user.build_address(@address.attributes) @user.save session["devise.regist_data"]["user"].clear sign_in(:user, @user) end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_up_params # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) # end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end protected def address_params params.require(:address).permit(:zipcode, :prefecture, :city,:district, :building, :room) end endapp/views/devise/registrations/create_address.html.erb<h2>登録が完了しました</h2> <%= link_to "トップへ戻る", root_path%>
- 投稿日:2020-08-07T18:54:01+09:00
Secretsantasができるまで① 事前準備〜ユーザ新規登録(ウィザード方式)
事前準備
- secretsantasという名のフォルダを作成し、VS codeで開く
- rails 5.0.7.2 new secretsantas -d mysql
- cd secretsantas
- rails db:create
- Githubに連携
- public/uploads/*を.gitignorenに追加
- http://localhost:3000/にアクセスしデフォルト画面を表示
user登録(ウィザード方式)
deviseを準備
Gemfileにdeviseを記述し、bundle install
Gemfilegem 'devise'アプリケーション内でdeviseのヘルパーメソッドなど使用するために以下のコマンドを叩く
$ rails g devise:installトップページを作成
config/routes.rbRails.application.routes.draw do root to: "home#index" endhomeコントローラを作成
$ rails g controller home******下
app/views/home/index.html.erb<h1>トップページが表示される</h1>ログインできるか確認
rails g devise userdb/migrate/20XXXXXX.rb# frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| ## Database authenticatable t.string :nickname, null: false t.string :first_name, null: false t.string :last_name, null: false t.string :first_name_kana, null: false t.string :last_name_kana, null: false t.date :birthday, null: false t.text :image, null: false t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable # t.string :confirmation_token # t.datetime :confirmed_at # t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :nickname, unique: true add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end$ rails db:migrateSequel Proでテーブルが作成されているか確認
次に、Appilication Controllerを修正します。nameやageなどのカラムを追加したためです。
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname,:first_name,:last_name, :first_name_kana, :last_name_kana,:birthday,:image]) end endカラムのバリデーションを設定
app/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable validates :nickname,:first_name,:last_name, :first_name_kana, :last_name_kana,:birthday,:image ,presence: true endビューをカスタマイズ
$ rails g devise:viewsapp/views/devise/registrations/new.html.erb<h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :nickname %><br /> <%= f.text_field :nickname %> </div> <div class="field"> <%= f.label :first_name %><br /> <%= f.text_field :first_name %> </div> <div class="field"> <%= f.label :last_name %><br /> <%= f.text_field :last_name %> </div> <div class="field"> <%= f.label :first_name_kana %><br /> <%= f.text_field :first_name_kana %> </div> <div class="field"> <%= f.label :last_name_kana %><br /> <%= f.text_field :last_name_kana %> </div> <div class="field"> <%= f.label :birthday %><br /> <%= f.date_field :birthday %> </div> <div class="field"> <%= f.label :image %><br /> <%= f.text_field :image %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Sign Up" %> </div> <% end %> <%= render "devise/shared/links" %>app/views/home/index.html.erb<h1>トップページ</h1> <% if user_signed_in?%> <h2>ログインしています</h2> <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> <% else %> <h2>ログインしていません</h2> <%= link_to "新規登録", new_user_registration_path %> <%= link_to "ログイン", new_user_session_path %> <% end %>新規登録できるか確認
deviseをカスタマイズしてウィザード形式の新規登録にする
$ rails g model addressdb/migrate/20XXXXX.rbclass CreateAddresses < ActiveRecord::Migration[5.0] def change create_table :addresses do |t| t.integer :zipcode, null: false t.string :prefecture, null: false t.string :city, null: false t.string :district, null: false t.string :building t.string :room t.references :user, foreign_key: true t.timestamps end end end$ rails db:migrateapp/models/address.rbclass Address < ApplicationRecord belongs_to :user, optional: true validates :zipcode, :prefecture, :city,:district,presence: true endapp/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable validates :nickname,:first_name,:last_name, :first_name_kana, :last_name_kana,:birthday,:image ,presence: true has_one :address end$ rails g devise:controllers usersconfig/routes.rbRails.application.routes.draw do devise_for :users, controllers: { registrations: 'users/registrations', } root to: "home#index" endapp/controllers/users/registrations_controller.rb# frozen_string_literal: true class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] def new @user = User.new end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_up_params # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) # end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end endapp/views/devise/registrations/new.html.erb<h2>ユーザー情報登録</h2> <%= form_for(@user, url: user_registration_path) do |f| %> <%= render "devise/shared/error_messages", resource: @user %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <div class="field"> <%= f.label :nickname %><br /> <%= f.text_field :nickname %> </div> <div class="field"> <%= f.label :first_name %><br /> <%= f.text_field :first_name %> </div> <div class="field"> <%= f.label :last_name %><br /> <%= f.text_field :last_name %> </div> <div class="field"> <%= f.label :first_name_kana %><br /> <%= f.text_field :first_name_kana %> </div> <div class="field"> <%= f.label :last_name_kana %><br /> <%= f.text_field :last_name_kana %> </div> <div class="field"> <%= f.label :birthday %><br /> <%= f.date_field :birthday %> </div> <div class="field"> <%= f.label :image %><br /> <%= f.text_field :image %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Next" %> </div> <% end %> <%= render "devise/shared/links" %>app/controllers/users/registrations_controller.rb# frozen_string_literal: true class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] def new @user = User.new end def create @user = User.new(sign_up_params) unless @user.valid? flash.now[:alert] = @user.errors.full_messages render :new and return end session["devise.regist_data"] = {user: @user.attributes} session["devise.regist_data"][:user]["password"] = params[:user][:password] @address = @user.build_address render :new_address end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_up_params # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) # end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end endconfig/routes.rbRails.application.routes.draw do devise_for :users, controllers: { registrations: 'users/registrations' } devise_scope :user do get 'addresses', to: 'users/registrations#new_address' post 'addresses', to: 'users/registrations#create_address' end root to: "home#index" endapp/views/devise/registrations/new_address.html.erb<h2>住所情報登録</h2> <%= form_for @address do |f| %> <%= render "devise/shared/error_messages", resource: @address %> <div class="field"> <%= f.label :zipcode %><br /> <%= f.text_field :zipcode %> </div> <div class="field"> <%= f.label :prefecture %><br /> <%= f.text_field :prefecture %> </div> <div class="field"> <%= f.label :city %><br /> <%= f.text_field :city %> </div> <div class="field"> <%= f.label :district %><br /> <%= f.text_field :district %> </div> <div class="field"> <%= f.label :building %><br /> <%= f.text_field :building %> </div> <div class="field"> <%= f.label :room %><br /> <%= f.text_field :room %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>app/controllers/users/registrations_controller.rb# frozen_string_literal: true class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] def new @user = User.new end def create @user = User.new(sign_up_params) unless @user.valid? flash.now[:alert] = @user.errors.full_messages render :new and return end session["devise.regist_data"] = {user: @user.attributes} session["devise.regist_data"][:user]["password"] = params[:user][:password] @address = @user.build_address render :new_address end def create_address @user = User.new(session["devise.regist_data"]["user"]) @address = Address.new(address_params) unless @address.valid? flash.now[:alert] = @address.errors.full_messages render :new_address and return end @user.build_address(@address.attributes) @user.save session["devise.regist_data"]["user"].clear sign_in(:user, @user) end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_up_params # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) # end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end protected def address_params params.require(:address).permit(:zipcode, :prefecture, :city,:district, :building, :room) end endapp/views/devise/registrations/create_address.html.erb<h2>登録が完了しました</h2> <%= link_to "トップへ戻る", root_path%>ユーザー登録のデザイン
- JQueryを使えるようにする
- fileをアップデートしてプレビューできるようにする
- 住所を自動入力できるようにする
- fontawesomeを使えるようにする
- reset.scssを追加する
- application.cssをscssに変更する
- 投稿日:2020-08-07T16:36:09+09:00
DockerでRailsチュートリアルのローカル開発環境構築 - WebpackでBootstrapとFont Awesomeを導入 -
はじめに
Dockerでローカル開発環境構築を行い、Railsチュートリアルを再走しております
- Railsチュートリアル最新版(2020.8.6現在)に対応のRails 6
- Dockerを使用し、開発環境の再現が可能
- なるべくローカル環境にインストールしない
今回はRailsチュートリアルの5章に相当する部分です
3章, 4章の内容は特に問題になりませんが、
5章 5.1.2 BootstrapとカスタムCSS の部分でいよいよWebpackの沼に突入して行きます
具体的にはgemを利用せず, YarnとWebpackでBootstrapやFont Awesomeを導入、管理します
加えてテストを書くことが増えるのでその辺りをRSpecで置き換えて進めていきます
5章終了時のブランチはfilling-in-layoutです
https://github.com/dev-naokit/sample_app_on_docker/tree/filling-in-layout第一回
DockerでRailsチュートリアルのローカル開発環境構築(Rails 6 + PostgreSQL + Webpack) - Qiita第二回
DockerでRailsチュートリアルのローカル開発環境構築 - RSpec導入 & CircleCIでHerokuデプロイ- - Qiita個人開発アプリ
mdClip <オンラインmarkdownエディタ>Dockerのコンテナ上で操作する場合はターミナルのコマンドを適宜
$ docker-compose run app ...もしくは
$ docker-compose exec app ...で置き換えてください。
BootstrapとFontawesomeの導入
Rails 6ではJavaScriptのモジュールバンドラとしてWebpackが導入されていますが、
画像やCSSに関しては従来のSprocketがアセットパイプラインとして使用され、
JavaScriptのみをWebpackでコンパイルするようになっていますapplication.html.erb
<head>
の内容を書き換えます
app/views/layouts/application.html.erb
<head> <title><%= full_title(yield(:title)) %></title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> # (下の行を追記)webpackがCSSを扱えるようにする <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> # JavaScriptはデフォルトでwebpacerが pack フォルダをコンパイルして出力している <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> <!--[if lt IE 9]> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"> </script> <![endif]--> </head>YarnでBootstrapをインストール
jquery
とpopper
はBootstrapに必要なパッケージ
Font Awesomeもあとで必要になるのでインストールします
('@fortawesome'は誤字ではありません)yarn add bootstrap jquery popper.js @fortawesome/fontawesome-freeインストールされたモジュールは
package.json
で確認できますapplication.js
app/javascript/packs/application.js
以下を追記します
require("bootstrap"); require("@fortawesome/fontawesome-free");
require('jquery')
も併記するような情報もありましたが、
Bootstrapが自動的にrequire('jquery')
してくれるようでココには記述不要です私も色々不具合を検証している過程で
require('jquery')
がなくてもjqueryがロードされることに気づいたのですが
jqueryの多重起動はJavaScriptの動作不具合につながることもあるようで、
現状はこのまま進めます(下に参考記事を貼っておきます)
environment.js
jQueryをどこからでも呼び出せるようにする
config/webpack/environment.js
const { environment } = require('@rails/webpacker') var webpack = require('webpack'); environment.plugins.append( 'Provide', new webpack.ProvidePlugin({ $: 'jquery/src/jquery', jQuery: 'jquery/src/jquery', Popper: ['popper.js', 'default'] }) ) module.exports = environmentこうすることで毎回
import $ from 'jquery';
と書かなくて良くなるとのことですCSS
app/javascript/stylesheets/application.scss
(新規作成)以下追記
@import '@fortawesome/fontawesome-free/scss/fontawesome'; @import 'bootstrap/scss/bootstrap';application.js
app/javascript/packs/application.js
以下を追記します
import '@fortawesome/fontawesome-free/js/all'; import "../stylesheets/application.scss";参考
Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
CSSの扱いについて
JavaScriptだけでなく画像やCSS、全てをWebpackでコンパイルすることも可能なようです
現状はSprocketによるアセットコンパイルと、Webpackerが共存している状況に変わりはなく
app/javascript/stylesheets/...
をコンパイルした内容が<head>
内の<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>で出力され
app/assets/stylesheets/...
をコンパイルした内容が同じく<head>
内の<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>に出力されている状況です
つまりチュートリアル通り
assets
内のCSS, SCSSを編集しても、
packs
内のCSS, SCSSを編集してもビューに反映される状況が出来上がっていますBootstrapやFont Awesomeのstyleは後者によってimportされ、コンパイル、ビューに反映されています
今後チュートリアルをすすめる上でどちらのStylesheetを編集しても問題ないと思いますが
<head>
内での呼び出しの順序くらいは気に留めて置いたほうがいいかもしれませんちなみに、
packs
内でCSSを編集する場合、webpack-dev-server
のHot reloadの恩恵を受けられます
具体的には、変更保存した場合に自動的にブラウザがリロードされ、即座に(やや遅延あり...)変更内容を確認できますRailsチュートリアルの流れで
custom.scss
を作成する場合
app/javascript/packs/application.js
に以下を記述すれば大丈夫ですimport "../stylesheets/custom.scss";(私はこの仕様で進めてみます)
Troubleshoot
Bootstrapのスタイルがおかしい
おそらくヘッダー周りが上手く表示されないと思います
Bootstrapのバージョンの違いによるものでこちらの記事の通りインストールすると
Bootstrapの最新版ver. 4.5(2020.8.7現在)が導入されます
(Railsチュートリアルでは3.4.1)navbar-inverseというタグがBootstrap 4では使用できなくなっていますので
<header class="navbar navbar-expand-md bg-dark navbar-dark bg-dark">で置き換えるなど細かな修正が必要です
修正を加えたこの章終了時のBranchを公開する予定ですが
yarn add
の際にバージョンを指定するといった対策も可能ですテストRSpec関連
assert_...
をどう書き換えるか?そのまま使えます
「RSpecでも assert xxx って書いてテストしたい」=> すぐできます! - Qiita
ApplicationHelperをテストでも使えるように...
include ApplicationHelper
を個別の_spec.rb
ファイルに記述もしくは、
spec/rails_helper.rb
に記述
各_spec.rb
でrequireされているので、個々に記述する必要はないはずですおわりに
この部分はRails 6環境で個人アプリ開発にあたり、最も苦労しました
身の丈に合わない内容で誤りを含むかもしれませんが
Railsチュートリアルの環境構築だけでなく、Rails 6環境でアプリ開発を行う方の一助になれば幸いです
- 投稿日:2020-08-07T13:31:24+09:00
必須項目ではないのにdeviseバリデーションが掛かってしまうときの対処法
こんな人におすすめ
・deviseを使ってログイン機能を持たせている
・任意の項目に意図せずバリデーションが掛かってしまう環境
ruby 2.5.1 Rails 5.0.7.2電話番号は任意にしたいが半角数字入力で制御したいのでバリデーションを掛ける
app/models/user.rb# Eメール・パスワード・パスワード確認は必須項目 validates :email, :password, :password_confirmation,presence: true # 電話番号は半角数字の入力でよい validates :tellphone_number, format: {with: /\A[0-9]+\z/, message:"半角数字でご入力ください。"}これだと、電話番号も必須項目扱いにされてしまいました。
解決策
1)電話番号のバリデーションに追記
追記前
app/models/user.rbvalidates :tellphone_number, format: {with: /\A[0-9]+\z/, message:"半角数字でご入力ください。"}追記後
app/models/user.rbvalidates :tellphone_number, uniqueness: true, format: {with: /\A[0-9]+\z/, message:"半角数字でご入力ください。"},on: :phone_number_validates # phone_number_validatesという名称は任意(後述のコントローラーで使用する時と同じであれば良い)2)合わせてコントローラーも追記
app/controllers/users_controller.rbdef update if current_user.update(user_params) redirect_to user_path(current_user.id) @phone_number.save(context: :phone_number_validates) # ここを追記 else render :edit end endこれで制御できるようになりました。
おわり。
- 投稿日:2020-08-07T12:29:37+09:00
アプリ作成の流れ④【パスワード認証機能】
前回は
検索機能を実装しました。
https://qiita.com/ksyantaro/private/af201b653cf55ad6f31c目次
- パスワード認証機能
パスワード認証機能
- メールアドレスとパスワードの2つを入力してデータベースに保存されているユーザーと一致したらログインさせるといった機能。
- SQLにおけるWHEREを指定してSELECT。
- 入力されたメールアドレスに一致するユーザーを取得して、入力されたパスワードが合っているかを判定する。
- パスワードはハッシュ化してデータベースに保存する。
gem 'devise'を使わずに実装していくこともできる
ただし、以下の記事からわかるように
- 自分で作ると脆弱性の可能性
- 車輪の再発明になる可能性
- 時間がかかる
といった問題点が出てきます。【参考記事】
問題点
https://teratail.com/questions/66458
作り方
https://qiita.com/kodaii/items/13b73cc687ee3b7db051deviseを使い、その仕組みを理解していくほうがいいのではないかという結論に至りました。
今回は'devise'で実装していく
'devise'によって、認証系の機能を簡単に実装することができる。
【参考記事】
deviseの使い方(rails6版)
https://qiita.com/cigalecigales/items/16ce0a9a7e79b9c3974edeviseのインストール
Gemfilegem 'devise'ターミナル% bundle install % rails g devise:install とすると以下のような記述が出てくる。 Running via Spring preloader in process 48598 create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Depending on your application's configuration some manual setup may be required: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. * Required for all applications. * 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" * Not required for API-only Applications * 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> * Not required for API-only Applications * 4. You can copy Devise views (for customization) to your app by running: rails g devise:views * Not required * ===============================================================================デフォルトURLの指定
config/environments_development.rbRails.application.configure do config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } endrootパスの指定
自分の場合はすでに指定しているので大丈夫。
指定していない場合はconfig/routesにて
rootを指定しよう。flashメッセージの追加
layouts/application.html.haml%body %p.notice = notice %p.alert = alert = yielddeviseのviewsを追加する
ターミナル% rails g devise:views
Userモデルを作成・編集する
Userモデルの作成
ターミナル% rails g devise user
nameカラムの追加
migrate/2020XXXXXXXXXX_devise_create_users.rbclass DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :name, null: false, default: "" t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ~~~~~~~~~~~省略しています~~~~~~~~~~~ t.timestamps null: false end add_index :users, :name, unique: true add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true end endmodels/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable 以下を追記しています! validates :name, presence: true, uniqueness: true end忘れずにrails db:migrateします!
controllers/application_controller.rbclass ApplicationController < ActionController::Base before_action :authenticate_user! before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) end endビューの編集
deviseのビューがerbなので、hamlに変更。
ターミナル% rails haml:erb2haml
nameの新規登録と編集ができるように
ログインはメールアドレスとパスワードでいけるようにします。
registrations/new.html.haml.field = f.label :name %br/ = f.text_field :name, autofocus: true, autocomplete: "name" これを追加します。 emailのものをコピーして少し編集するのがおすすめ。 email_fieldはtext_fieldにしましょう。registrations/edit.html.haml.field = f.label :name %br/ = f.text_field :name, autofocus: true, autocomplete: "name" - if devise_mapping.confirmable? && resource.pending_reconfirmation? %div Currently waiting confirmation for: #{resource.unconfirmed_name} これを追加します。 emailのものをコピーして少し編集するのがおすすめ。 email_fieldはtext_fieldにしましょう。ログイン時とログアウト時の表示の変更
layouts/application.html.haml%body %header %nav - if user_signed_in? %strong = link_to current_user.name, blog_path(current_user.id) = link_to 'プロフィール変更', edit_user_registration_path = link_to 'ログアウト', destroy_user_session_path, method: :delete - else = link_to 'サインアップ', new_user_registration_path = link_to 'ログイン', new_user_session_path %p.notice = notice %p.alert = alert = yieldまとめ
以上でdeviseを用いた
簡単なパスワード認証機能は実装できました。次回はSNS認証の実装をしていきたいと思います。
- 投稿日:2020-08-07T11:53:29+09:00
編集、削除の権限を投稿者だけにしたい
バージョン
・ruby 2.5.7
・Rails 5.2.4.3編集、削除の権限を投稿者だけにしたい
CRUD処理は出来た!
けど、このままだと全ての投稿を編集や削除が出来てしまう状態。
編集、削除の権限を投稿者だけの機能にしたい。
ユーザーの投稿を守る為に下記のメソッドを使う
unlessはもし〜でなかったらと言う意味。下記でいうと、
もし受け取ったユーザーのIDが、ログインしているユーザー(current_user)のIDと一致しなければ、処理を実行せずリダイレクトで戻しますよっていう意味です。
before_actionでメソッドを呼び出して、完成!!!
before_actionはコントローラーの全てのアクションが実行される前に実行されるものです。
今回は編集と削除のみの場合で行いたいので、editとupdateとdestroyのみにしています。
- 投稿日:2020-08-07T10:15:48+09:00
rails5中級チュートリアルのテストがうまく通らなかった時
前提・実現したいこと
rails5中級チュートリアルを行なっています。
チュートリアルの3-3でのテストの部分で
昨日から以下のエラーが発生し、テストをパスすることができず、困っていた。発生している問題・エラーメッセージ
ターミナルでのrspec spec/features/user/login_spec.rb実行時
1) Login ユーザーがloginページにリダイレクトされ、ログインに成功する Failure/Error: expect(page).to have_selector('#user-settings') expected to find css "#user-settings" but there were no matches # ./spec/features/user/login_spec.rb:13:in `block (2 levels) in <top (required)>' Finished in 4.17 seconds (files took 2.75 seconds to load) 1 example, 1 failure Failed examples: rspec ./spec/features/user/login_spec.rb:6 # Login ユーザーがloginページにリダイレクトされ、ログインに成功する該当のソースコード
login_spec.rbrequire "rails_helper" RSpec.feature "Login", :type => :feature do let(:user) { create(:user) } scenario 'ユーザーがloginページにリダイレクトされ、ログインに成功する', js: true do user visit root_path find('nav a', text: 'ログイン').click fill_in 'user[email]', with: user.email fill_in 'user[password]', with: user.password find('.login-button').click expect(page).to have_selector('#user-settings') end end試したこと
①エラー文で検索をかけるも、手がかりを見つけることができなかった。
②エラー文にcssの"#user-setting"とhave_selectorの"#user-setting"が一致しないとあるため、cssの"#user-setting"に問題があると仮説するが、そもそもcssに"#user-setting"というものがなくどうすれば良いのかすらわからない状態であった。
③vscodeの文字列検索で[user-setting]と検索した際に、[_signed_in_links.html.erb]ファイル内でuser-settingをidとして定義してある箇所があったためそちらの記述を"#user-setting"に変更してみたが、解決することができなかった。
_signed_in_links_html.erb<li class="dropdown pc-menu"> # この下の行の"user-settingを変更を試した" <a id="user-setting" class="dropdown-toggle" data-toggle="dropdown" href="#"> <span id="user-name"><%= current_user.name %></span> <span class="caret"></span> </a> <ul class="dropdown-menu" role="menu"> <li><%= link_to 'プロフィールを編集', edit_user_registration_path %></li> <li><%= link_to 'ログアウト', destroy_user_session_path, method: :delete%></li> </ul> </li> <li class="mobile-menu"> <%= link_to 'プロフィールを編集', edit_user_registration_path %> </li> <li class="mobile-menu"> <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %> </li>解決方法
一日以上時間を費やしては埒が明かないと考え,teratailで質問を投げかけたところ解決。
上記にある試したこと③にもある_signed_in_links_html.erbでのid指定を#user-settingsではなく
user-settingsに修正したところテストを通過することができた。学び
cssセレクタでは、#はid属性、.の場合はclss属性ということを完全に忘れてしまっていた。
補足情報(FW/ツールのバージョンなど)
vscode最新バージョン使用
railsバージョン 5.1.7
bootstrapテストツール
factory_bot_rails
capybara 2.15
rspec-rails
selenium-webdriver
rails-controller-testing
headless
poktergeist
- 投稿日:2020-08-07T07:57:15+09:00
リダイレクトはしたい。だがQueryParameterは失いたくない。
そんな時はこう。
get '/users/new', to: redirect(path: "users/sign_up")Parameterは据置でpathだけ変更してくれるのさ。
- 投稿日:2020-08-07T07:38:10+09:00
Ruby on Railsのシード機能についてのメモ
はじめに
初心者です。
RubyとRuby on Railsを使ってアプリケーションを作っています。
備忘録も兼ねておりますので、間違いなどあればご指摘ください。シード機能とは
データベース作成後に、初期データを簡単に流し込むことができる機能。
どのファイルを使うのか
db/seeds.rb
に初期データとして流し込みたいコードを記述して、
ターミナルでrails db:seed
すればOK。
実行してもターミナルに何か表示されるわけではないが、データに問題なければ流し込まれているはず。ファイルにはどう記述するのか
例)productsテーブルのnameカラムとdescriptionカラムにデータを5つ流し込む
5.times do |i| Product.create(name: "Product ##{i}", description: "A product.") endtimesメソッドを使っているが、1行ずつ書いていっても問題なし。
まとめ
- シード機能はデータベース作成後に初期データを流し込むことができる機能
db/seeds.rb
に流し込みたいデータを記述- ターミナルで
rails db:seed
すれば流し込める参考
Railsガイドv6.0
https://railsguides.jp/active_record_migrations.html
- 投稿日:2020-08-07T00:22:04+09:00
DockerでRailsチュートリアルのローカル開発環境構築 - RSpec導入 & CircleCIでHerokuデプロイ-
はじめに
前回の記事
DockerでRailsチュートリアルのローカル開発環境構築(Rails 6 + PostgreSQL + Webpack) - Qiita個人開発アプリ
mdClip <オンラインmarkdownエディタ>前回の記事に続いて、Railsチュートリアルのローカル開発環境構築を行っていきます。
Railsチュートリアル最新版(2020.8.6現在)に対応のRails 6
Dockerを使用し、開発環境の再現が可能
なるべくローカル環境にインストールしない
Docker環境で操作する場合はターミナルのコマンドを適宜
$ docker-compose run app ...もしくは
$ docker-compose exec app ...で置き換えてください。
Rspec導入
minitestでも問題ないです
後述のCircleCIでもminitestを走らせる事もできました。Gemfile
必要に応じて以下のgemを追加
(不要ならminitest関連のgemを削除する)
Gemfile
# Test enviroment: Rspec gem 'rspec-rails' gem 'spring-commands-rspec' gem 'guard' gem 'guard-rspec', require: false # Test enviroment: Fake date generator gem 'factory_bot_rails' gem 'faker' gem 'forgery_ja'bundle install
Gemfileを編集したので
docker-compose build
が必要です$ docker-compose build初期ファイル生成
$ rails g rspec:installレポートフォーマット
.rspec
--require spec_helper --format documentationGuard初期化
$ bundle exec guard initspring boot対応
$ bundle exec spring binstub --allGuardの自動テスト時にもspringが有効になるように
Guardfile
$ guard :rspec, cmd: "bundle exec spring rspec" doCircleCI設定
事前準備
ここでは説明しませんが事前に以下の手順が必要だと思います
- GitHub & CircleCI & Herokuのアカウント登録
- SSH接続設定(GitHub - CircleCI)
- CircleCIへのproject登録および環境変数定義(Heroku APIキー, app名)
設定概要
git push
-> 自動test (RSpec) -> 自動デプロイ(Heroku)- Orbを使うと
config.yml
の内容を簡略化できる(キャッシュ利用のための記述が不要)- Orbを使うために
version: 2.1
指定- Docker imageのRuby versionはRailsチュートリアルに合わせて2.6.3
- Node.jsが必要なので-nodeのついたimageを指定
メモ: Node.js バリアントの Docker イメージ (
-node
で終わるタグ) に対しては、Node.js の LTS リリースがプリインストールされています。 独自に特定のバージョンの Node.js/NPM を使用する場合は、.circleci/config.yml
内のrun
ステップで設定できます。 Ruby イメージと共に特定のバージョンの Node.js をインストールする例については、以下を参照してください。公式サンプルを踏襲しています
公式do - Ruby
Language Guide: Ruby - CircleCI公式doc - Heroku Deploy
デプロイの構成 - CircleCI現時点で最新のHeroku-orbは1.2.0ですがバグがあるようで
pull request
されています
deploy-via-git bash script error · Issue #13 · CircleCI-Public/heroku-orbconfig.yml
.circleci/config.yml
version: 2.1 orbs: ruby: circleci/ruby@1.0 node: circleci/node@2 heroku: circleci/heroku@1.1.0 # setupでまとめる commands: setup: steps: - checkout - ruby/install-deps - node/install-packages: pkg-manager: yarn cache-key: "yarn.lock" jobs: build: docker: - image: circleci/ruby:2.6.3-node steps: - setup test: docker: - image: circleci/ruby:2.6.3-node - image: circleci/postgres:11.6-alpine environment: POSTGRES_USER: postgres POSTGRES_DB: myapp_test POSTGRES_PASSWORD: "" environment: BUNDLE_JOBS: "4" BUNDLE_RETRY: "3" PGHOST: 127.0.0.1 PGUSER: postgres PGPASSWORD: "" RAILS_ENV: test steps: - setup - run: name: Wait for DB command: dockerize -wait tcp://localhost:5432 -timeout 1m - run: name: Database setup command: bundle exec rails db:schema:load --trace - run: name: Rspec command: bundle exec rspec deploy: executor: heroku/default steps: - checkout - heroku/install - heroku/deploy-via-git: maintenance-mode: true - run: name: DB migrate command: heroku run rails db:migrate --app $HEROKU_APP_NAME workflows: version: 2 test_and_deploy: jobs: - build - test: requires: - build - deploy: requires: - build - test filters: branches: only: master動作確認
HTMLを書き換える
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base def hello render html: "Bye, world!" end end変更をgit pushして、CircleCIのpipelineがsuccessに変われば
ブラウザから見た内容が上記を反映するはずです簡単なテスト
仮のrequest_specを作成
rails g rspec:request test
spec/requests/tests_spec.rb
require 'rails_helper' RSpec.describe "Tests", type: :request do describe "GET /" do it "Bye, world!が表示されること" do get root_path expect(response.body).to include "Bye, world!" end end endCircleCI上でも上記テストがpassするはずです
Troubleshoot
CircleCIのtestが以下のエラーで失敗する
rails aborted! PG::ConnectionBad: could not translate host name "db" to address: Name or service not known
database.yml
の記述が原因ですtest環境ではdefaultを引き継いで
host: db
が適応されているはずです
config/database.yml
以下のように書き換えて環境変数がある場合はそちらを優先するようにしました
(ymlのなかでもerbが使えるという学びでした)test: <<: *default host: <%= ENV['PGHOST'] || 'db' %> database: myapp_testERROR IN CONFIG FILE:
インデント、フォーマットの間違いが多いと思います
最後に
- 意地でローカル環境をきれいに保つことに注力した結果、デプロイやdb:migrateを自動化することで、Heroku CLIすらインストールすることを回避しましたが、素直にHeroku CLIくらいは入れておいた方が今後のエラー解決に役立つ気もします。
- 難易度は上がりますが、ローカル環境でDocker, CICDを取り入れてのRailsチュートリアル、学べることも多いと思いますので腰を据えて取り組むことのできる方はぜひトライしてみてください。
- 今後も未知のエラーに遭遇することが予想されますが、おおよそココまでが大変なところかとおもっていますので、この記事がお役に立てれば幸いです。
- 投稿日:2020-08-07T00:01:21+09:00
Rails開発で役立つVSCodeの拡張機能
プログラミングの勉強日記
2020年8月7日 Progate Lv.226
VSCodeでRailsアプリケーション開発するうえで便利だなと思った拡張機能をまとめてみる。VSCode拡張機能のインストール方法
- 左端のバーから拡張機能を選択する
- 検索ボックスにインストールしたい拡張機能の名前を入力
- インストールしたい拡張機能を選択し、インストールをクリック
Rails開発で便利な拡張機能
Ruby
Ruby言語のサポートをする。Rubyのベーシックなシンタックスハイライト(テキストエディタなどの文字表示に関する機能の1つで、特定のキーワードや記号を色を変えたりフォントを変えたりして見やすいように表示する)や入力候補を提供する。
Ruby Language Colorization
Rubyのシンタックスハイライトを提供する。
endwise
Rubyを書くときに忘れやすい
end
を自動で入力してくれる。Rails
Railsをサポートする。Railsのスニペット(コードの断片)やナビゲーションを提供する。
Ruby Solargraph
Rubyの入力予測をより強化してくれる。(Rails拡張機能を入れるとインストールされる)
Rails Go to Spec
Windowsの場合は
Cmd + Shift + y
のショートカットで対応するspecファイルと行き来ができる。ERB
erbのシンタックスハイライトを提供する。
Slim
Slim使ってる方はこちらで、、
Rainbow End
end
を色分けする拡張機能。参考文献
VSCodeでRuby on Railsを開発するなら絶対に入れたいおすすめ拡張機能7選
VSCodeの拡張機能でRailsと仲良くなる