Nhóm lồng nhau bởi javascript

Chào mọi người, bài viblo của mình hôm nay sẽ nói về Nested Attributes và Nested Form cách sử dụng gem cocoon

Giới thiệu về Nested Attributes

Trước khi nói về các thuộc tính lồng nhau và biểu mẫu lồng nhau, chúng ta cần xem xét các vấn đề sau

Giả sử chúng ta dự án có chức năng đăng ký người dùng. Trong bảng cơ sở dữ liệu sẽ có bảng Người dùng có tên trường, địa chỉ, tuổi

Khi đăng ký người dùng mới, chúng ta chỉ có thể lưu 1 bản ghi tên, địa chỉ, tuổi với người đó thôi đúng k?

Nếu người dùng muốn thêm nhiều địa chỉ thì sao?

Thì có 1 cách thêm nhiều địa chỉ vào trường add user nhưng như thế sẽ rất khó lấy ra save vì quá nhiều thuộc tính vào 1 cột

Còn 1 cách khác nữa là thêm nhiều địa chỉ trường nhưng như thế sẽ là mã cứng, muốn thêm địa chỉ thì phải thêm 1 trường khác trong cơ sở dữ liệu

Cách cuối cùng, cũng là cách ổn định và khả thi nhất, đó là tách bảng Người dùng ra thành 2 bảng khác nhau

Như hình ở trên, chúng ta đã tách ra và có 2 bảng là Người dùng và bảng Hồ sơ

Để thêm đc địa chỉ vào bảng profile thì có rất nhiều cách trong đó có thuộc tính lồng nhau là cách ổn định nhất

Với các thuộc tính lồng nhau, chúng ta có thể lưu đồng thời dữ liệu ở bảng user và bảng profile trong cùng 1 biểu mẫu mà không cần thêm nhiều biểu mẫu khác nhau

Mình sẽ demo bên dưới để các bạn có thêm về ví dụ sử dụng các thuộc tính lồng nhau

Với các thuộc tính lồng nhau, bạn có thể thêm một hoặc nhiều trường địa chỉ khác nhau

Đồng nghĩa với việc người dùng sẽ có nhiều địa chỉ

Khi tạo người dùng mới, nó sẽ thực hiện câu lệnh sql để chèn người dùng mới vào cơ sở dữ liệu Và nó cũng sẽ chèn 2 bản ghi mới vào bảng hồ sơ, với địa chỉ là "Hà Nội" và "Hồ Chí Minh" như chúng tôi đã nhập

Cách phát triển khai thác Nested Attributes

Đầu tiên, chúng ta cần tách thành 2 bảng User và Profile Sau đó, để 2 bảng này có thể liên kết với nhau, chúng ta sẽ sử dụng Association

class User < ApplicationRecord
  has_many :profiles, dependent: :destroy
 end
class Profile < ApplicationRecord
  belongs_to :user
end

Để bảng người dùng có thể lồng các thuộc tính bảng hồ sơ thì chúng ta cần phải sử dụng câu lệnh này

accepts_nested_attributes_for 

VD

class User < ApplicationRecord

  has_many :profiles, dependent: :destroy

  accepts_nested_attributes_for :profiles, allow_destroy: true,
    reject_if: :all_blank
end

in which. profile là tên liên kết, allow_destroy. đúng, từ chối_if. . all_blank is the option of it

Allow_destroy. đúng nghĩa là cho phép xóa bản ghi con, ở đây là xóa các địa chỉ từ người dùng đó, reject_if. all_bank, nếu các trường Địa chỉ bị trống thì nó sẽ không lưu bản ghi đó vào cơ sở dữ liệu

Ngoài ra, chúng ta có thể từ chối nếu chỉ định tên các thuộc tính khác nhau

reject_if. tiến hành {. thuộc tính. thuộc tính['params']. trống?

VD. reject_if. tiến hành {. thuộc tính. thuộc tính['địa chỉ']. trống?

Sau đó qua phần điều khiển đền

class UsersController < ApplicationController
  def new
    @user = User.new
    user.profiles.new
  end

  def create
    @user = User.new user_params
    if user.save
      notice_redirect
    else
      user.profiles || user.profiles.new
      render :new
    end
  end

  private
  
  def user_params
    params.require[:user].permit :email, :password, :name,
      :password_confirmation, profiles_attributes: [:address, :_destroy]
  end
end

Tiếp theo chúng ta qua phần điều khiển, hành động mới. Chúng tôi khai báo người dùng. Hồ sơ. mới để có thể khởi tạo 1 đối tượng người dùng mới nhưng chưa lưu vào cơ sở dữ liệu Khởi tạo càng nhiều đối tượng hồ sơ mới thì càng có nhiều trường để chúng ta điền vào, xây dựng hồ sơ 2 lần thì có 2 hồ sơ đối tượng mới, =>2 địa chỉ trường

tạo hành động. lưu người dùng mới vào cơ sở dữ liệu, ở đây cần lưu các thông số truyền vào người dùng

Khi tạo, cập nhật đối tượng người dùng, chúng ta đồng thời có thể tạo, cập nhật luôn hồ sơ đối tượng bằng cách truyền thuộc tính của hồ sơ vào thông số của người dùng

Chúng ta có profile_attributes. [. địa chỉ,. _hủy hoại]

Slide before have said về allow_destroy. đúng, để có thể xóa các thuộc tính lồng nhau chúng ta phải có _destroy trong thông số của hồ sơ thì mới hoạt động dc,. address is params to save the address into database


  
  
  


Sau khi đã cấu hình đầy đủ về các thuộc tính lồng nhau

Chúng ta phải thiết lập biểu mẫu để có thể lưu nhiều địa chỉ của 1 người dùng vào cơ sở dữ liệu

Ở đây chúng ta sử dụng field_for để lưu địa chỉ field_for giống như 1 cái biểu mẫu của hồ sơ được sử dụng để nhập nhiều địa chỉ khác nhau mà chúng ta muốn. hồ sơ là tên hiệp hội

address is field has in table profile

Nhược điểm và giải quyết

Tuy các thuộc tính lồng nhau có rất nhiều lợi ích nhưng nó cũng có những nhược điểm như là nó không hoạt động?

Giả sử người dùng muốn thêm nhiều địa chỉ hơn số trường mình đã định sẵn thì sao? . Người dùng không thể thêm 1 trường địa chỉ khác, không cần tải lại trang trên trình duyệt mà phải dựa vào mã người ra trang web đó

Để giải quyết vấn đề đó, chúng ta sẽ sử dụng Nested Form với Cocoon Nhưng trước khi sử dụng Cocoon, tôi muốn bạn xem nguyên lí hoạt động của Cocoon nhờ vào việc sử dụng Nested Form sử dụng Javascript thuần túy

Biểu mẫu lồng nhau sử dụng Javascript thuần túy

Để hiểu rõ về mẫu lồng nhau mời bạn xem ví dụ dưới đây

Ở đây có 1 nút là Thêm địa chỉ, bạn có thêm địa chỉ trường khác ngay trên trình duyệt mà không phải tải lại trang

1 địa chỉ trường khác đã được thêm sau khi nhấn

Nguyên lí hoạt động của nested form là nó sẽ thêm 1 cái form vào bên trong nút Add Address, khi người dùng click vào, nó sẽ nối cái form đó ra trình duyệt nhờ sử dụng javascript

Triển khai

Vẫn sử dụng các thuộc tính lồng nhau, chúng ta sẽ chỉnh sửa lại 1 chút như hình trên

Trong trường đó sẽ tải vào dữ liệu, trong trường truyền vào phương thức sub_address_field [dữ liệu chính là thuộc tính Dữ liệu trong javascript, nó sẽ giúp bạn lưu thêm thông tin vào thẻ html] Nó sẽ truyền vào dữ liệu để có thể sử dụng trong javascript

Ứng dụng/người trợ giúp/application_helper. rb

module ApplicationHelper
  def sub_address_field form
    sub_address = form.object.profiles.build
    form.fields_for :profiles, sub_address,
      child_index: "hello" do |builder|
      render "profiles_fields", f: builder
    end
  end
end

Trong phương thức sub_address_field

sub_address, start profile of form. đối tượng với đối số là biểu mẫu [ở đây f chính của @user chúng ta truyền vào biểu mẫu]

hình thức. fields_for,tạo ra 1 cái thuộc tính dạng lồng nhau như bình thường

con_index. chính là chỉ mục của các biểu mẫu lồng nhau, cần nó để id và tên không bị trùng lặp, nếu bị trùng lặp thì sẽ không thể tạo dc các nội dung khác nhau

Tiếp theo, chúng ta sẽ tạo 1 file javascript với nội dung như sau

ứng dụng/nội dung/javascript/thuộc tính lồng nhau. js

________số 8

Khi nhấp vào phần tử với id là trường con

Nó sẽ lấy dữ liệu của cái này, cái này ở đây chính được gọi tới trường con id

dữ liệu ở đây là trường chúng ta nói ở hình ảnh trước

new_id, get current time

Câu lệnh bên dưới, sẽ thêm vào trường trong lớp sub_address. Nghĩa là nó sẽ nối thêm 1 cái từ bên trong trường và nối vào lớp sub_address

/helio/g với /g sử dụng biểu thức chính quy, tìm tất cả các chữ là hello, instead with new_id

Nhược điểm và giải quyết

Tuy chúng ta đã có thể lồng vào biểu mẫu nhưng cách làm vẫn giữ ra và không hiệu quả do sử dụng javascript thuần. Mình sẽ hướng dẫn các bạn sử dụng gem Cocoon để có thể nhanh chóng tạo ra dạng lồng nhau mà lại dễ sử dụng và rút gọn

Cocoon vẫn sẽ cho ra chức năng tỏa sáng tương tự như khi lồng nhau từ dạng với javascript thuần túy, nhưng nó sẽ đơn giản và dễ sử dụng hơn rất nhiều

Cocoon triển khai

Để sử dụng Cocoon, các bạn thêm gem vào trong gemfile

class Profile < ApplicationRecord
  belongs_to :user
end
0

Sau đó yêu cầu nó vào trong ứng dụng. js

class Profile < ApplicationRecord
  belongs_to :user
end
1

Vẫn sử dụng các thuộc tính lồng nhau

class Profile < ApplicationRecord
  belongs_to :user
end
2

Chúng ta chỉ cần kết xuất 1 phần và truyền vào đối tượng cho nó

link_to_association, chính là đường liên kết để hiện biểu mẫu khác cần sử dụng, thêm địa chỉ là tên liên kết, chính là đối tượng mà biểu mẫu đang sử dụng với. profile là tên của các thuộc tính lồng nhau

Và bên trong cái partial này có gì?

ứng dụng/chế độ xem/người dùng/_profile_fields. html. erb

class Profile < ApplicationRecord
  belongs_to :user
end
3

Bên trong là các thuộc tính mà chúng ta muốn sử dụng để lồng các thuộc tính, ở đây là địa chỉ

link_to_remove_association, used to delete cái lồng nhau form đó đi Lưu ý là link_to_remove_association chỉ hoạt động với class "nested-fields"

Chủ Đề