Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Edit object with HABTM association modify database before validation with ActiveAdmin

I Having an issue when trying to update a model that has has_and_belongs_to_many association.

Let's say that Post has_and_belongs_to_many Tag, and Post validates the presence of title and Tags. If I update Post, removing its title and tags, I get validation error in title and tags, ok. But ActiveAdmin already removed the records that make association between Post and Tag, so, if I leave Post edit page, the post is left invalid on database, without tags.

Here my models:

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

I usign chosen-rails gem and it allows user to unselect all tags of post.

Summarizing, my problem is: ActiveAdmin updates relationships on database before perform model validations.

There a solution for this behavior or I doing something wrong?

Edit:

Here the request log when I trying to update post without title and tags:

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/ruby-1.9.3-p125@blog/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, I sure that ActiveAdmin has this bug.

Looking at ActiveRecord behaviour, I think that validation flow is broken using only model class. See this example:

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 

Has any way to update post attributes(including tags) and validate the model before doing any database update?

like image 595
Rodrigo Avatar asked Nov 03 '22 01:11

Rodrigo


1 Answers

You can use this gem: https://github.com/MartinKoerner/deferred_associations

The deferred associations will fix this bug.

like image 78
Victor Lellis Avatar answered Nov 11 '22 11:11

Victor Lellis