views:

62

answers:

0

I have two quite nasty problems with join model. I think I am just going wrong way, so maybe someone can clear up my approch a bit. First there are some models with realtions like this:

class Account < ActiveRecord::Base
  has_many :tickets, :through => :assigment
  has_many :assigments
  ...
end

accepts_nested_attributes_for :assigments, :allow_destroy => true
attr_accessible :assigments_attributes

============

class Ticket < ActiveRecord::Base
  has_many :accounts, :through => :assigment
  has_many :assigments
  ...
end

============

class Assigment < ActiveRecord::Base
  validates_uniqueness_of :ticket_id, :scope => [:account_id]
  belongs_to :account
  belongs_to :ticket
  ...
end

There is a fairly simple form for for users, where one can select tickets for a person. I have a view with a bit of javascript. I used the approach mentioned by Ryan Bats in http://railscasts.com/episodes/197-nested-model-form-part-2 There is something like this in the view:

- f.fields_for :assigments do |b|
   = f.collection_select :ticket_id, Ticket.all, :id, :code
   = f.hidden_field :_destroy
   [...]

User can select available ticket from list and he can click "add" to add another list to pick next ticket. Everything is done without any kind of hacks and stuph.

Now there's few problems with this approch. In the select user can pick a ticket, and he can pick the same ticket in the next select. Now this is moreless validated byt the validates_uniqueness_of in Assigment. The error is returned, when user picks same task twice. Idealy I would like to silenty allow that kind of choice, but clean up the choices on the server side. There is a "del" js link, which sets _destroy to 1, but I would like allow users to pick "None" from the select with the same select.

After user selects the tasks I tried some ways to clear up the chocies by:

def validate_assigments  
  # delete assigment if selected task is blank
  assigments.each do |m|
    m.delete if m.task.blank?          
  end
  hash = Hash.new    
  assigments.all.each do |e| 
    hash[e.task_id] = e
  end  
  objs = assigments.all - hash.values    
  objs.each do |o| 
    o.destroy 
  end  
end

First the idea is to remove assigments, which have tasks set to none. The other idea, is to remove assigments with duplicated keys from the hash.

Is this the right direction? I have various issues with the above. Sometimes it works, but lot of times I get mixed results with weird erros and I can't find the real reason.

Another problem raises when users switches the tasks. When user has Tasks "A" and "B" and then he switches to task "B" in first select and to task "A" in second select. This happens fairly often, when users tries to clean up the list of tasks. I think that records are validaed one-by-one in assigments, so it fails to switch A->B, since that assigment fails the validates_uniqueness_of in assigments.

Are there any big flaws in my approch? Are there any good tutorials or examples with forms / validations and a join model. I will have a lot of such relations in my application and I think I am missing something important.

btw: If users have no assigments, then "f.fields_for :assigments do |b|" doesn't generate any select fields in the view. I have an "if" in my code, to generate new empty select if thats the case:

- if @user.assigments.count == 0
  = generate_first_empty_select_helper ...

Is that idea right? Is that nessecery to put separate code for that kind of event?

I am farily new to Rails, btw, so please don't be harsh. :-)

Big thanks for any tips!