Config gem devise with has_one assosiation

Xin chào các bạn, hôm nay chúng ta sẽ tìm hiểu về gem devise với has_one assosiation.

Trong bài viết này chúng ta sẽ tìm hiểu cách làm sao để tạo form cho 1 user với 1 address.

#user.rb
class User < ApplicationRecord
  has_one :address
end
class Address < ApplicationRecord
  belongs_to :user
end
  1. Đầu tiên, chúng ta sẽ tìm hiểu về gem devise.

install gem

#gem
gem "devise"
#bundle install

install devise

#terminal
rails generate devise:install

config mailer

#config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end

generate devise for user:

#terminal
  rails generate devise user

sau đó chạy: rake db:migrate thêm các devise cần thiết cho user như đăng nhập, đăng xuất ...

#user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable

khai báo routes cho những modul mình sử dụng. như ở dưới đây là đăng nhập đăng ký và thay đổi password khi quên.

  devise_for :users, controllers: {
    sessions: "users/sessions",
    registrations: "users/registrations",
    passwords: "users/passwords"
  }

Như vậy chúng ta đã install thành công gem devise.

ở gem này chúng ta có thêm một số hàm đặc trưng để kiểm tra đăng nhập:

before_action :authenticate_member!
member_signed_in?
current_member
member_session
  1. tiếp theo chúng ta thêm address cho user bằng hasone assosiate

chúng ta thêm nested attribute cho user

#user.rb
accepts_nested_attributes_for :address, allow_destroy: true

sau đó config lại class Users::RegistrationsController < Devise::RegistrationsController để hiển thị form và save data.

#Users::RegistrationsController
  before_action :configure_sign_up_params, only: :create
  before_action :configure_account_update_params, only: :update

  def new
    build_resource {}
    self.resource.address = Address.new
    respond_with self.resource
  end

  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up) {|u| u.permit :email,
      :phone_number, :name, :password, :password_confirmation,
      address_attributes: [:city, :town, :village, :home_number]}
  end

  def configure_account_update_params
    devise_parameter_sanitizer.permit(:account_update) {|u| u.permit :name,
      :password, :password_confirmation}
  end

Ở đây chúng ta phải config lại hàm khởi tạo đối tượng user của gem devise.

build_resource {} sẽ trả về 1 object resource, và mình có thể build address nested bằng cách self.resource.address = Address.new và trả về đối tượng user đã được thay đổi respond_with self.resource.

Bên cạnh đó chúng ta cũng cần viết nested cho param bằng cách gọi before_action :configure_sign_up_params, only: :create khi create và before_action :configure_account_update_params, only: :update khi update.

Cuối cùng ở view chúng ta sẽ build ra form cho việc thêm 1 user với 1 address.


# app/views/users/registrations/new.html.erb

<h1><%= t "devise.edit_register", resource: resource_name.to_s.humanize %></h1>
<div class="col-md-6 col-md-offset-3">
  <%= form_for resource, as: resource_name, url: registration_path(resource_name), html: {method: :put} do |f| %>
    <%= render "shared/error_messages", object: resource %><br />

    <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
      <div><%= t "devise.email_confirm_edit_registration", resource: resource.unconfirmed_email %></div>
    <% end %>

    <div class="field">
      <%= f.label :password %> <i>(<%= t "devise.password_cant_blank" %>)</i>
      <%= f.password_field :password, autocomplete: "off", class: "form-control" %>
      <% if @minimum_password_length %>
        <br />
      <% end %>
    </div>

    <div class="field">
      <%= f.label :password_confirmation %>
      <em>(<%= t "devise.password", number_of_password: @minimum_password_length %>)</em>
      <%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %>
    </div>

    <div class="field">
      <%= f.label :current_password %> <i>(<%= t "devise.need_current_password" %>)</i>
      <%= f.password_field :current_password, autocomplete: "off", class: "form-control" %>
    </div>
    <br />
    <div class="actions">
      <%= f.submit t("devise.update"), class: "btn btn-primary" %>
    </div>
  <% end %>
</div>

Như vậy chúng ta đã hoàn thành config cho gem devise với hasone assosiation. Has_one là một trong những assosiation ít được sử dụng trong khi viết web nên sẽ có 1 chút khó khăn nhất định, nhưng nó cũng không quá khó để tim hiểu.

Chúng các bạn thành công. Cám ơn các bạn đã xem bài viết của mình.

link tham khảo: https://github.com/plataformatec/devise