Polymorphic Associations in Rails - Part 02
This post hasn't been updated for 8 years
Ở 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