2013-03-27 30 views
5

Tôi gặp sự cố khi cố gắng cập nhật mô hình có liên kết has_and_belongs_to_many.Chỉnh sửa đối tượng với cơ sở dữ liệu sửa đổi liên kết HABTM trước khi xác nhận với ActiveAdmin

Giả sử Posthas_and_belongs_to_manyTagPost xác thực sự hiện diện của tiêu đề và Tags. Nếu tôi cập nhật Post, xóa tiêu đề và thẻ, tôi nhận được lỗi xác thực trong titletags, ok. Nhưng ActiveAdmin đã xóa các bản ghi liên kết giữa PostTag, vì vậy, nếu tôi rời khỏi trang chỉnh sửa Post, thì post sẽ không hợp lệ trên cơ sở dữ liệu, mà không có tags.

Dưới đây mô hình của tôi:

class Tag < ActiveRecord::Base 
    attr_accessible :label 
    has_and_belongs_to_many :posts 
end 

class Post < ActiveRecord::Base 
    attr_accessible :content, :title, :tag_ids 
    has_and_belongs_to_many :tags 
    validates_presence_of :content, :title, :tags 
end 

ActiveAdmin.register Post do 

    form do |f| 
    f.inputs do 
     f.input :title 
     f.input :content 
     f.input :image 
     f.input :tags 
    end 

    f.buttons 
    end 
end 

tôi usign chosen-rails đá quý và nó cho phép người sử dụng để bỏ chọn tất cả các thẻ của bưu điện.

Tóm tắt, vấn đề của tôi là: ActiveAdmin cập nhật các mối quan hệ trên cơ sở dữ liệu trước khi thực hiện xác thực mô hình.

Có một giải pháp cho hành vi này hoặc tôi làm điều gì đó sai?

Edit:

Đây nhật ký yêu cầu khi tôi cố gắng cập nhật bài viết mà không tiêu đề và các thẻ:

Started PUT "/admin/posts/8" for 127.0.0.1 at 2013-04-01 10:32:07 -0300 
Processing by Admin::PostsController#update as HTML 
    Parameters: {"utf8"=>"✓", "authenticity_token"=>"amSbLlP/rgDrNn/N8lgq/KEaRXK1fMPShZDwpZ0QIJ4=", "post"=>{"title"=>"", "content"=>"content", "tag_ids"=>["", ""]}, "commit"=>"Update Post", "id"=>"8"} 
    AdminUser Load (0.2ms) SELECT `admin_users`.* FROM `admin_users` WHERE `admin_users`.`id` = 1 LIMIT 1 
    Post Load (0.2ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 8 LIMIT 1 
    Tag Load (0.2ms) SELECT `tags`.* FROM `tags` INNER JOIN `posts_tags` ON `tags`.`id` = `posts_tags`.`tag_id` WHERE `posts_tags`.`post_id` = 8 
    (0.1ms) BEGIN 
    SQL (12.3ms) DELETE FROM `posts_tags` WHERE `posts_tags`.`post_id` = 8 AND `posts_tags`.`tag_id` IN (1, 2) 
    (49.6ms) COMMIT 
    (0.1ms) BEGIN 
    (0.2ms) ROLLBACK 
    Post Load (0.3ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 8 LIMIT 1 
    Tag Load (0.2ms) SELECT `tags`.* FROM `tags` 
    Rendered /home/rodrigo/.rvm/gems/[email protected]/gems/activeadmin-0.5.1/app/views/active_admin/resource/edit.html.arb (192.3ms) 
Completed 200 OK in 276ms (Views: 194.8ms | ActiveRecord: 63.3ms) 

EDIT 2:

Ok, tôi chắc chắn rằng ActiveAdmin có lỗi này.

Nhìn vào hành vi ActiveRecord, tôi cho rằng luồng xác thực bị hỏng chỉ sử dụng lớp mô hình. Xem ví dụ này:

1.9.3p125 :064 > post = Post.find(8) 
    Post Load (0.3ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 8 LIMIT 1 
=> #<Post id: 8, title: "title", content: "content", created_at: "2013-03-27 13:13:20", updated_at: "2013-03-27 13:13:20", image: "extrato.bmp"> 
1.9.3p125 :065 > post.tags 
    Tag Load (0.2ms) SELECT `tags`.* FROM `tags` INNER JOIN `posts_tags` ON `tags`.`id` = `posts_tags`.`tag_id` WHERE `posts_tags`.`post_id` = 8 
=> [#<Tag id: 1, label: "tag", created_at: "2013-02-25 18:32:45", updated_at: "2013-02-25 18:32:45">, #<Tag id: 2, label: "new", created_at: "2013-02-25 18:32:50", updated_at: "2013-02-25 18:32:50">] 
1.9.3p125 :066 > post.title = "" 
=> "" 
1.9.3p125 :067 > post.save #<<<<<<< It's invalid on title 
=> false 
1.9.3p125 :068 > post.tags = [] #<<<<<<< This shouldnt trigger database update 
    (0.3ms) BEGIN 
    SQL (0.5ms) DELETE FROM `posts_tags` WHERE `posts_tags`.`post_id` = 8 AND `posts_tags`.`tag_id` IN (1, 2) 
    (55.5ms) COMMIT 
=> [] 
1.9.3p125 :069 > post.save #<<<<<<< It's invalid on title AND TAGS 
    (0.2ms) BEGIN 
    (0.2ms) ROLLBACK 
=> false 
1.9.3p125 :070 > post.reload 
    Post Load (0.2ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 8 LIMIT 1 
=> #<Post id: 8, title: "title", content: "content", created_at: "2013-03-27 13:13:20", updated_at: "2013-03-27 13:13:20", image: "extrato.bmp"> 
1.9.3p125 :071 > post.valid? #<<<<<<< Now, I have this model in invalid state 
    Tag Load (0.6ms) SELECT `tags`.* FROM `tags` INNER JOIN `posts_tags` ON `tags`.`id` = `posts_tags`.`tag_id` WHERE `posts_tags`.`post_id` = 8 
=> false 

Có cách nào để cập nhật thuộc tính bài (bao gồm thẻ) và xác thực mô hình trước khi thực hiện bất kỳ cập nhật cơ sở dữ liệu nào không?

+0

Bạn không nên có tag_ids trong bài viết của bạn mô hình. Bạn có bảng trung gian trong cơ sở dữ liệu của bạn sẽ phù hợp với mối quan hệ habtm? – Zippie

+0

@Zippie, tôi không có 'tag_ids' trong mô hình của mình. ActiveAdmin chỉ định id của các thẻ trong bài đăng bằng phương thức này do Rails tạo. – Rodrigo

+0

âm thanh lạ, hãy sao chép đính kèm nhật ký truy vấn sql theo yêu cầu của bạn – Fivell

Trả lời

-1

nếu bạn muốn, bạn có thể xác định lại bạn cập nhật hành động trong active_admin để ngăn chặn tiết kiệm thẻ trống, trong một cái gì đó giống như phong cách này

ActiveAdmin.register Post do 

    controller do 
    def update 
     if params[:post][:tag_ids] == ["", ""] 
     flash.now[:alert] = "You can't remove all tags" 
     render :edit 
     else 
     super 
     end 
    end 
    end 
... 
end 

và tôi nghĩ rằng công cụ này từ mô hình có thể bị xóa

attr_accessor :new_tag_ids 

validate :validate_new_tags_ids 

after_save :update_tags 

def update_tags 
    self.tag_ids = @new_tag_ids if defined?(@new_tag_ids) 
    @new_tag_ids = nil 
end 

private 
def validate_new_tags_ids 
    errors[:tags] << "can't be blank (2)" if @new_tag_ids.blank? 
end 
+0

Tôi không muốn làm điều đó cho tất cả các mô hình của tôi. Nó sẽ hoạt động mà không có bất kỳ công việc xung quanh. – Rodrigo

+0

Trong mọi trường hợp bạn cần một công việc xung quanh, vấn đề của bạn trong thuộc tính tag_ids, thuộc tính này được tự động phát hiện bởi liên kết has_many đường ray. Bạn chuyển đến tham số tag_ids và khi nó thiết lập thành thuộc tính, nó lưu liên kết. post.tags = [] sẽ xóa tất cả các thẻ, vì vậy bạn cần đổi tên thẻ_id trong chế độ xem của bạn và xử lý đúng cách –

+0

Vì vậy, bạn đang nói rằng bạn không thể chỉ định thẻ cho Đăng và xác thực thẻ trước khi lưu các liên kết mới này? – Rodrigo

1

@Rodrigo Tôi có thể tạo lại vấn đề của bạn cục bộ mà không cần quản trị viên tích cực, vấn đề thực sự là một trong các hoạt động mặc định khi sử dụng mối quan hệ HABTM nếu bạn thấy [ở đây] [1]

[1]: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_and_belongs_to_many nó nói:

bộ sưu tập = đối tượng

Replaces the collection’s content by deleting and adding objects as appropriate. 

Vì vậy, rõ ràng bạn sẽ cần phải ghi đè hoạt động này

Dưới đây là một ví dụ:

Override ActiveRecord << operator on has_many :through relationship, to accept data for the join model

Hãy cho tôi biết làm cách nào tôi có thể giúp bạn

0

Tôi muốn đề xuất thêm biến tmp và lưu trữ các giá trị trong đó. Sau đó, bạn nên chuyển chúng vào cơ sở dữ liệu nếu xác thực được thông qua.

Dưới đây là một ví dụ:

bạn models/article.rb:

class Article < ActiveRecord::Base 
    validate :author_presence 
    has_and_belongs_to_many :authors 

    attr_writer :tmp_author_ids 

    def tmp_author_ids 
    @tmp_author_ids || author_ids 
    end 

    def author_presence 
    if tmp_author_ids.reject(&:blank?).empty? 
     errors.add(:tmp_author_ids, 'Author is missing') 
    else 
     self.author_ids = tmp_author_ids 
    end 
    end 
end 

bạn admin/article.rb, chặn form:

f.input :tmp_author_ids, as: :select, multiple: true, collection: Author.all, label: 'Authors' 

Vậy đó

Các vấn đề liên quan