blue workbench

Ruby and Rails

【Rails】seeds.rbを書く

前提

app/models/product.rb

# frozen_string_literal: true

class Product < ApplicationRecord
  has_one :stock
end

app/models/stock.rb

# frozen_string_literal: true

class Stock < ApplicationRecord
  belongs_to :product
end

書く

db/seeds.rb

# frozen_string_literal: true

5.times do |n|
  Product.create!(
    name: "商品#{n + 1}",
    price: 10_000
  )
end

Product.all.each do |product|
  product.create_stock!(
    quantity: 99
  )
end

実行

DBを作り直す必要がなければ、rails db:seed のみでOKです。

(DBを作成し直すなら)
$ rails db:migrate:reset

$ rails db:seed

ちなみに rails db:reset はDBを db/schema.rb から作り直して、そのままrails db:seed を実行しているようです。
(勝手にデータが入っている)

$ rails db:reset

参考

qiita.com

easyramble.com

【Rails】deviseのvalidatableを理解する

validatableモジュールのソースコード

devise/models/validatable.rb

# frozen_string_literal: true

module Devise
  module Models
    # Validatable creates all needed validations for a user email and password.
    # It's optional, given you may want to create the validations by yourself.
    # Automatically validate if the email is present, unique and its format is
    # valid. Also tests presence of password, confirmation and length.
    #
    # == Options
    #
    # Validatable adds the following options to devise_for:
    #
    #   * +email_regexp+: the regular expression used to validate e-mails;
    #   * +password_length+: a range expressing password length. Defaults to 6..128.
    #
    module Validatable
      # All validations used by this module.
      VALIDATIONS = [:validates_presence_of, :validates_uniqueness_of, :validates_format_of,
                     :validates_confirmation_of, :validates_length_of].freeze

      def self.required_fields(klass)
        []
      end

      def self.included(base)
        base.extend ClassMethods
        assert_validations_api!(base)

        base.class_eval do
          validates_presence_of   :email, if: :email_required?
          if Devise.activerecord51?
            validates_uniqueness_of :email, allow_blank: true, case_sensitive: true, if: :will_save_change_to_email?
            validates_format_of     :email, with: email_regexp, allow_blank: true, if: :will_save_change_to_email?
          else
            validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
            validates_format_of     :email, with: email_regexp, allow_blank: true, if: :email_changed?
          end

          validates_presence_of     :password, if: :password_required?
          validates_confirmation_of :password, if: :password_required?
          validates_length_of       :password, within: password_length, allow_blank: true
        end
      end

      def self.assert_validations_api!(base) #:nodoc:
        unavailable_validations = VALIDATIONS.select { |v| !base.respond_to?(v) }

        unless unavailable_validations.empty?
          raise "Could not use :validatable module since #{base} does not respond " <<
                "to the following methods: #{unavailable_validations.to_sentence}."
        end
      end

    protected

      # Checks whether a password is needed or not. For validations only.
      # Passwords are always required if it's a new record, or if the password
      # or confirmation are being set somewhere.
      def password_required?
        !persisted? || !password.nil? || !password_confirmation.nil?
      end

      def email_required?
        true
      end

      module ClassMethods
        Devise::Models.config(self, :email_regexp, :password_length)
      end
    end
  end
end

インクルードされるバリデーション

フィールド バリデーション
メールアドレス validates_presence_of
validates_uniqueness_of
validates_format_of
パスワード validates_presence_of
validates_confirmation_of
validates_length_of

パラメータを追加した場合

パラメータを追加したならば、いつものように手で書くのがよさそうです。

app/models/user.rb

# frozen_string_literal: true

class User < ApplicationRecord
  devise :database_authenticatable,
         :validatable,
         :registerable,
         :recoverable,
         :rememberable,
         :confirmable

  validates :screen_name,
            presence: true,
            length: { maximum: 20 },
            uniqueness: { case_sensitive: false }
end

参考

github.com

【Rails】deviseでemail, password以外のサインアップパラメータを追加する

やりたいこと

サインアップするためのパラメータに、email, password以外に screen_name というパラメータを追加したい。

前提

以下の手順を完了していること。 (DBのカラムは以下手順で追加済みです)

now-on-air.hatenablog.com

手順

$ rails g devise:views users
Running via Spring preloader in process 68444
      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/users/shared
      create    app/views/users/shared/_error_messages.html.erb
      create    app/views/users/shared/_links.html.erb
      invoke  simple_form_for
      create    app/views/users/confirmations
      create    app/views/users/confirmations/new.html.erb
      create    app/views/users/passwords
      create    app/views/users/passwords/edit.html.erb
      create    app/views/users/passwords/new.html.erb
      create    app/views/users/registrations
      create    app/views/users/registrations/edit.html.erb
      create    app/views/users/registrations/new.html.erb
      create    app/views/users/sessions
      create    app/views/users/sessions/new.html.erb
      create    app/views/users/unlocks
      create    app/views/users/unlocks/new.html.erb
      invoke  erb
      create    app/views/users/mailer
      create    app/views/users/mailer/confirmation_instructions.html.erb
      create    app/views/users/mailer/email_changed.html.erb
      create    app/views/users/mailer/password_change.html.erb
      create    app/views/users/mailer/reset_password_instructions.html.erb
      create    app/views/users/mailer/unlock_instructions.html.erb
group :development do
  gem 'html2haml'
end
$ bundle install
$ find . -name \*.erb -print | sed 'p;s/.erb$/.haml/' | xargs -n2 html2haml
$ find app/views -name \*.erb
app/views/users/unlocks/new.html.erb
app/views/users/passwords/edit.html.erb
app/views/users/passwords/new.html.erb
app/views/users/mailer/confirmation_instructions.html.erb
app/views/users/mailer/reset_password_instructions.html.erb
app/views/users/mailer/password_change.html.erb
app/views/users/mailer/email_changed.html.erb
app/views/users/mailer/unlock_instructions.html.erb
app/views/users/shared/_error_messages.html.erb
app/views/users/shared/_links.html.erb
app/views/users/sessions/new.html.erb
app/views/users/confirmations/new.html.erb
app/views/users/registrations/edit.html.erb
app/views/users/registrations/new.html.erb
$ find app/views -name \*.haml
app/views/layouts/application.html.haml
app/views/layouts/mailer.text.haml
app/views/layouts/mailer.html.haml
app/views/users/unlocks/new.html.haml
app/views/users/passwords/edit.html.haml
app/views/users/passwords/new.html.haml
app/views/users/mailer/unlock_instructions.html.haml
app/views/users/mailer/reset_password_instructions.html.haml
app/views/users/mailer/password_change.html.haml
app/views/users/mailer/confirmation_instructions.html.haml
app/views/users/mailer/email_changed.html.haml
app/views/users/shared/_links.html.haml
app/views/users/shared/_error_messages.html.haml
app/views/users/sessions/new.html.haml
app/views/users/confirmations/new.html.haml
app/views/users/registrations/edit.html.haml
app/views/users/registrations/new.html.haml
$ find app/views -name \*.erb | xargs rm
$ find app/views -name \*.erb

app/views/users/registrations/new.html.haml

%h2 ユーザー登録
= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
  = f.input :screen_name, autofocus: true
  = f.input :email, autocomplete: 'email'
  = f.input :password, autocomplete: 'new-password'
  = f.input :password_confirmation, autocomplete: 'new-password'
  = f.button :submit
= render "users/shared/links"
$ rails g devise:controllers users
Running via Spring preloader in process 91047
      create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

  Ensure you have overridden routes for generated controllers in your routes.rb.
  For example:

    Rails.application.routes.draw do
      devise_for :users, controllers: {
        sessions: 'users/sessions'
      }
    end

===============================================================================

config/routes.rbdevise_for :users の部分を以下のように修正します。

  devise_for :users, controllers: {
      registrations: 'users/registrations'
  }

app/controllers/application_controller.rb を以下のようにします。keys: [:screen_name] のところに今回追加したい screen_name を入れます。

# frozen_string_literal: true

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

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:screen_name])
  end
end

参考

github.com