How do I use has_many :through and in_place_edit?
I have two Models: Campaign and Contact.
A Campaign has_many Contacts.
A Contact has_many Campaigns.
Currently, each Contact has a contact.date_entered attribute. A Campaign uses that date as the ate to count down to the different Events that belong_to the Campaign.
However, there are situations where a Campaign for a specific Contact may need to be delayed by X number of days. In this instance, the campaigncontact.delaydays = 10.
In some cases, the Campaign must be stopped altogether for the specific Contact, so for now I set campaigncon开发者_StackOverflowtact.delaydays = 1. (Are there major problems with that?)
By default, I am assuming that no campaigncontact exists (but not sure how that works?)
So here's what I've tried to do:
class Contact < ActiveRecord::Base
has_many :campaigncontacts
has_many :campaigns, :through => :campaigncontacts
end
class Campaign < ActiveRecord::Base
has_many :campaigncontacts
has_many :contacts, :through => :campaigncontacts
end
script/generate model campaigncontact campaign_id:integer contact_id:integer delaydays:integer
class Campaigncontact < ActiveRecord::Base
belongs_to :campaign
belongs_to :contact
end
So, here's the question: Is the above correct? If so, how do I allow a user to edit the delay of a campaign for a specific Contact.
For now, I want to do so from the Contact View.
This is what I tried:
In the Contact controller (?)
in_place_edit_for :campaigncontact, column.delaydays
And in the View
<%= in_place_editor_field :campaigncontact, :delaydays %>
How can I get it right?
I would add an integer field to your Campaigncontacts resource called days_to_delay_communication_by, since this information relates to the association of a campaign and a contact rather than a contact itself.
in your migration:
def self.up
add_column(:campaigncontacts, :days_to_delay_communication_by, :integer)
end
def self.down
remove_column(:campaigncontacts, :days_to_delay_communication_by)
end
Now you can set that value by:
campaigncontact = Campaigncontacts.find(:first, :conditions => { :campaign_id => campaign_id, :contact_id => contact_id })
campaigncontact.days_to_delay_communication_by = 10
Then in the admin side of your application you can have a controller and a view for campaign communications that lets you set the days_to_delay_communication_by field for campaigncontacts. I can expand on this further for you if you're interested, but I think you get the idea.
Then you'll need to run a background process of some sort (probably a cron job, or use the delayed_job plugin), to find communications that haven't happened yet, and make them happen when the date has passed. You could do this in a rake task like so:
namespace :communications do
namespace :monitor do
desc 'Monitor and send communications for campaigns'
task :erma => :environment do
Rails.logger.info "-----BEGIN COMMUNICATION MONITORING-----"
unsent_communications = Communication.all(:conditions => { :date_sent => nil})
unsent_communications.each do |communication|
Rails.logger.info "**sending communication**"
communication.send if communication.time_to_send < Time.now
Rails.logger.info "**communication sent**"
end
Rails.logger.info "-----END COMMUNICATION MONITORING-----"
end #end erma task
end #end sync namespace
end #end db namespace
Then your cron job would do something like:
cd /path/to/application && rake communications:monitor RAILS_ENV=production
Also, I'd consider changing the name of your join model to something more descriptive of it's purpose, for instance memberships, a campaign has many memberships and a contact has many memberships. Then a membership has a days_to_delay_communication field.
A good way to do this is use a "fake" attribute on your Contact model like so:
class Contact < ActiveRecord::Base
has_many :campaigncontacts
has_many :campaigns, :through => :campaigncontacts
attr_accessor :delay
def delay #edit
self.campaigncontacts.last.delaydays
end
def delay=(val)
self.campaigncontacts.each do |c|
c.delaydays = val
end
end
end
Then just set the in_place_editor for this fake field:
in_place_edit_for :contact, :delay
and
<%= in_place_editor_field :contact, :delay %>
I'm not sure I understood exactly what you wanted to accomplish, but I hope this at least points you into the right direction.
精彩评论