+1

Polymorphic Associations in Rails - Part 02

Ở phần trước mình đã viết bài tìm hiểu về đa hình trong Rails, trình bày tóm tắt và đưa ra ví dụ về mối quan hệ này. Phần tiếp theo này mình viết thêm chi tiết hơn về một ví dụ sử dụng mối quan hệ này.

Bài toán đặt ra như sau: Bạn có một website bán hoa (gọi là shop hoa Tết) chẳng hạn, khi ấy người dùng vào website của bạn và ghé thăm các mẫu hoa trưng bày trên website của bạn và bạn muốn cho họ có thể ghim lại các mẫu hoa mà họ thích vào danh sách yêu thích của họ.

Bài viết này mình sẽ xây dựng chức năng này trên Rails app.

Step 1 - Setup new app

Create new app (ex: r_shop)

rails new r_shop

Step 2 - Setup authentication use devise

Mình dùng gem devise cho User login, logout, v..v.. cho hệ thống này.

Thêm gem 'devise' vào Gemfile

# Gemfile
gem 'devise'
bundle install

Chạy lệnh sau để install devise cho app của mình.

rails generate devise:install

Tạo model User

rails generate devise User

Migration database

rake db:migrate

Step 3 - Setup model and relations

Phần này mình sẽ tạo một model để lưu trữ các mẫu hoa, mình gọi tên là Post, mình ví dụ mỗi mẫu hoa có tiêu đề (title) và phần mô tả (content). Tùy theo mô hình của bạn mà thiết kế khác.

Create Post.rb

rails g scaffold post title:string content:text

Tiếp theo, mình gọi danh sách yêu thích của người dùng tên là Wishlist. Tạo model Wishlist.rb

rails g scaffold wishlist user_id:integer wishlistable_id:integer wishlistable_type:string

Cài đặt quan hệ cho models

#wishlist.rb
class Wishlist < ActiveRecord::Base
  belongs_to :wishlistable, polymorphic: true
end
#post.rb
class Post < ActiveRecord::Base
  has_many :wishlists, as: :wishlistable
end
#user.rb
class User < ActiveRecord::Base
  has_many :posts
end

Step 4 - Fake database

Phần này mình sẽ tạo giả một số bản ghi trong cơ sở dữ liệu để tiện cho việc demo.

Sử dụng gem faker

# Gemfile

gem 'faker', '1.4.2'

run command to install

bundle install

Mình sẽ tạo ra 1 user và 50 posts trong cơ sở dữ liệu.

# seeds.rb

User.create (email: "admin@test.com",
             password:              "12345678",
             password_confirmation: "12345678",
            )

50.times do
  title = Faker::Lorem.sentence(2)
  content = Faker::Lorem.sentence(4)
  Post.create title: title, content: content, user_id: 1
end

Import vào database

rake db:seed

Step 5 - Build wishlist function use ajax

Đầu tiên mình viết 1 hàm để kiểm tra xem mẫu hoa đó đã được đưa vào danh sách yêu thích của người dùng hay chưa.

# post.rb
def wish_by? user
  wishlists.exists? user_id: user
end

Tiếp theo, tạo chức năng trên giao diện web. Tại trang xem mẫu hoa (show post) mình tạo nút bấm để đưa mẫu này vào danh sách yêu thích hoặc bỏ ra khỏi danh sách yêu thích nếu đã có trong danh sách yêu thích của người dùng.

#app/views/posts/show.html.erb

<% if user_signed_in? %>
  <div id="wish_box">
    <%= render "shared/actions", obj: @post %>
  </div>
<% end %>

Tạo file render actions bên trên.

#shared/_actions.html.erb

<% if obj.wish_by? current_user %>
  <% wishlist = Wishlist.find_by_wishlistable_id(obj.id) %>
  <%= form_for wishlist, html: {method: :delete}, remote: true do |f| %>
    <button type="submit" class="btn add-to-wish">
      <i class="fa fa-times"></i>
      <%= t("wishlist.remove") %>
    </button>
  <% end %>
<% else %>
  <%= form_for obj.wishlists.build(user_id: current_user.id), remote: true do |f| %>
    <%= f.hidden_field :user_id %>
    <%= f.hidden_field :wishlistable_id, value: obj.id %>
    <%= f.hidden_field :wishlistable_type, value: obj.class.name %>
    <button type="submit" class="btn add-to-wish">
      <i class='fa fa-heart-o'></i>
      <%= t("wishlist.add") %>
    </button>
  <% end %>
<% end %>

Chỉnh sửa phần controller wishlist_controller.rb

# wishlist_controller.rb

def create
  @object = params[:wishlist][:wishlistable_type]
  @obj = @object.constantize.find(params[:wishlist][:wishlistable_id])
  @wishlist = Wishlist.new(wishlist_params)
  @wishlist.user_id = current_user.id
  respond_to do |format|
    if @wishlist.save
      format.html { redirect_to @wishlist, notice: 'Wishlist was successfully created.' }
      format.js
    else
      format.html { render :new }
      format.json { render json: @wishlist.errors, status: :unprocessable_entity }
    end
  end
end

def destroy
  @obj = Wishlist.find(params[:id]).wishlistable
  @wishlist.destroy
  respond_to do |format|
    format.html { redirect_to wishlists_url, notice: 'Wishlist was successfully destroyed.' }
    format.js
  end
end

Như vậy là đã xong, mình đã xây dựng được chức năng wishlistable sử dụng ajax.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.