Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveAdmin / Formtastic sortable has_many through relationship

I may be missing something fundamental here, but I can't seem to get ActiveAdmin to work with a sortable has_many through relationship, with the ability to create new records.

So given the following models

class User < ActiveRecord::Base

  has_many :user_videos
  has_many :videos, through: :user_videos

  accepts_nested_attributes_for :user_videos
  accepts_nested_attributes_for :videos

  ...
end

class UserVideo < ActiveRecord::Base

  belongs_to :user
  belongs_to :video

  accepts_nested_attributes_for :video

end

class Video < ActiveRecord::Base

  has_many :user_videos
  has_many :users, through: :user_videos

  ...
end

(I admit I'm throwing accepts_nested_attributes_for around somewhat in the hopes that something may work)

And Active Admin setup goes something like this (WIP of course):

f.inputs "User" do
  f.has_many :user_videos, heading: 'Videos', sortable: :order, allow_destroy: true, new_record: 'New Record' do |v|
    v.inputs for: :video do |video|
      video.input :video_url
    end
  end
  f.has_many :videos, heading: 'Videos', new_record: 'New Video' do |v|
    v.input :video_url
  end
end

f.actions

The first has_many on the :user_videos association does not seem to render any inputs. If there are records there, I can see that video.input :video_url is actually returning an li tag with label and input, however nothing gets rendered to the page. For new records the whole v.inputs bit does not get run (do I need to create the child records somehow there first?).

The second has_many will work in that you'll be able to add records, and update existing records, however it's impossible to sort as the order column is on the UserVideos model. I include this more as illustration than anything.

If anyone has any pointers for this, they would be most appreciated. :)

like image 252
Sam Peacey Avatar asked Oct 18 '22 01:10

Sam Peacey


2 Answers

WHOA! I know I am late to the party, but this is a perfect opportunity to utilize the :delegate method!

Your UserVideo class would look something like this

class UserVideo < ActiveRecord::Base

  belongs_to :user
  belongs_to :video

  validates_with VideoValidator

  delegate :video_url, :video_url=, to: :video
end

Best of luck!

like image 190
Kyle Boss Avatar answered Oct 29 '22 19:10

Kyle Boss


Since nobody seemed interested in tackling this, I took another approach - rather than trying to get ActiveAdmin / Formtastic to work with the existing model structure, I added getters and setters for the necessary field on the intersection model.

class UserVideo < ActiveRecord::Base

  belongs_to :user
  belongs_to :video

  validates_with VideoValidator

  def video_url
    self.video = Video.create if video.nil?
    self.video.video_url
  end

  def video_url=(video_url)
    self.video = Video.create if video.nil?
    self.video.video_url = video_url
    # Video url is set via Active Admin, AA will not call save on the video as it does not realise it's changed
    self.video.save! if video.present? and video.valid?
  end

end

Doing this meant that Active Admin did not need to know about the Video model, and could just operate on the UserVideo model:

  f.has_many :user_videos, heading: 'Videos', sortable: :order, allow_destroy: true, new_record: 'New Record' do |v|
    v.input :video_url, :hint => (v.object.video.embed_code unless v.object.nil? or v.object.video.nil?)
  end

If anyone has an actual solution rather than a work around, I'd love to hear it, but otherwise this is a possible solution for anyone searching for an answer to the same problem.

like image 36
Sam Peacey Avatar answered Oct 29 '22 19:10

Sam Peacey