has_emails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,23 @@
1
+ *SVN*
2
+
3
+ *0.0.1* (September 26th, 2007)
4
+
5
+ * Refactor has_email_address/has_email_addresses so that new associations for unsent/sent emails isn't created for has_email_address
6
+
7
+ * Add state changes fixtures for tests
8
+
9
+ * Add tests for ApplicationMailer
10
+
11
+ * Add support for tracking the original email address for senders/recipients even if the email address changes on the associated model (i.e. EmailAddress/User/etc.)
12
+
13
+ * Support converting models with an email_address/email_addresses association
14
+
15
+ * Allow the sender of emails to be an arbitrary string email address
16
+
17
+ * Add documentation
18
+
19
+ * Move test fixtures out of the test application root directory
20
+
21
+ * Convert dos newlines to unix newlines
22
+
23
+ * Update against latest changes to has_messages
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006-2007 Aaron Pfeifer & Neil Abraham
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,130 @@
1
+ = has_emails
2
+
3
+ +has_emails+ adds support for emailing capabilities between ActiveRecord models.
4
+
5
+ == Resources
6
+
7
+ API
8
+
9
+ * http://api.pluginaweek.org/has_emails
10
+
11
+ Wiki
12
+
13
+ * http://wiki.pluginaweek.org/Has_emails
14
+
15
+ Announcement
16
+
17
+ * http://www.pluginaweek.org
18
+
19
+ Source
20
+
21
+ * http://svn.pluginaweek.org/trunk/plugins/active_record/has/has_emails
22
+
23
+ Development
24
+
25
+ * http://dev.pluginaweek.org/browser/trunk/plugins/active_record/has/has_emails
26
+
27
+ == Description
28
+
29
+ Emailing between users and other parts of a system is a fairly common feature in
30
+ web applications, especially for those that support social networking. Emailing
31
+ doesn't necessarily need to be between users, but can also act as a way for the
32
+ web application to send notices and other notifications to users.
33
+
34
+ Rails already provides ActionMailer as a way of sending emails. However, the
35
+ framework does not provide an easy way to persist emails, track their status, and
36
+ process them asynchronously. Designing and building this type of framework can
37
+ become complex and cumbersome and takes away from the focus of the web application.
38
+ This plugin helps ease that process by providing a complete implementation for
39
+ sending and receiving emails to and between models in your application.
40
+
41
+ == Usage
42
+
43
+ === Adding emailing support
44
+
45
+ If you want to use the built-in support for email addresses (using the EmailAddress
46
+ model), you can add emailing support for users like so:
47
+
48
+ class User < ActiveRecord::Base
49
+ has_email_address
50
+ # has_email_addresses if you want to support multiple addresses
51
+ end
52
+
53
+ On the other hand, if you already have the email address for users stored as a
54
+ column in your users table, you can add emailing support like so:
55
+
56
+ class User < ActiveRecord::Base
57
+ has_messages :emails,
58
+ :message_class => 'Email'
59
+ end
60
+
61
+ === Creating new emails
62
+
63
+ email = user.emails.build
64
+ email.to << [user1, email_address1, 'someone@somewhere.com']
65
+ email.subject = 'Hey!'
66
+ email.body = 'Does anyone want to go out tonight?'
67
+ email.deliver!
68
+
69
+ As can be seen in the above example, you can use Users, EmailAddresses, or even
70
+ Strings as recipients in emails. Each will be automatically converted to the
71
+ EmailRecipient class so that it can be stored in the database.
72
+
73
+ === Replying to emails
74
+
75
+ reply = email.reply_to_all
76
+ reply.body = "I'd love to go out!"
77
+ reply.deliver!
78
+
79
+ === Forwarding emails
80
+
81
+ forward = email.forward
82
+ forward.body = 'Interested?'
83
+ forward.deliver!
84
+
85
+ === External process messaging
86
+
87
+ In addition to delivering emails immediately, you can also *queue* emails so
88
+ that an external application processes and delivers them. This is especially
89
+ useful when you want to asynchronously send e-mails so that it doesn't block the
90
+ user interface on your web application.
91
+
92
+ To queue emails for external processing, you can simply use the <tt>queue!</tt>
93
+ event, rather than <tt>deliver!</tt>. This will indicate to any external processes
94
+ that the email is ready to be sent. The external process can then invoke <tt>deliver!</tt>
95
+ whenever it is ready to send the queued email.
96
+
97
+ === Running migrations
98
+
99
+ To migrate the tables required for this plugin, you can either run the
100
+ migration from the command line like so:
101
+
102
+ rake db:migrate:plugins PLUGIN=has_emails
103
+
104
+ or (more ideally) generate a migration file that will integrate into your main
105
+ application's migration path:
106
+
107
+ ruby script/generate plugin_migration has_emails
108
+
109
+ == Testing
110
+
111
+ Before you can run any tests, the following gems must be installed:
112
+ * plugin_test_helper[http://wiki.pluginaweek.org/Plugin_test_helper]
113
+ * dry_validity_assertions[http://wiki.pluginaweek.org/Dry_validity_assertions]
114
+
115
+ == Dependencies
116
+
117
+ This plugin depends on the presence of the following plugins:
118
+ * has_messages[http://wiki.pluginaweek.org/Has_messages]
119
+
120
+ This plugin is also a plugin+. That means that it contains a slice of an
121
+ application, such as models and migrations. To test or use a plugin+, you
122
+ must have the following plugins/gems installed:
123
+ * plugin_dependencies[http://wiki.pluginaweek.org/Plugin_dependencies]
124
+ * loaded_plugins[http://wiki.pluginaweek.org/Loaded_plugins]
125
+ * appable_plugins[http://wiki.pluginaweek.org/Appable_plugins]
126
+ * plugin_migrations[http://wiki.pluginaweek.org/Plugin_migrations]
127
+
128
+ Instead of installing each individual plugin+ feature, you can install them all
129
+ at once using the plugins+[http://wiki.pluginaweek.org/Plugins_plus] meta package,
130
+ which contains all additional features.
data/Rakefile ADDED
@@ -0,0 +1,81 @@
1
+ require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/contrib/sshpublisher'
5
+
6
+ PKG_NAME = 'has_emails'
7
+ PKG_VERSION = '0.0.1'
8
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
9
+ RUBY_FORGE_PROJECT = 'pluginaweek'
10
+
11
+ desc 'Default: run unit tests.'
12
+ task :default => :test
13
+
14
+ desc 'Test the has_emails plugin.'
15
+ Rake::TestTask.new(:test) do |t|
16
+ t.libs << 'lib'
17
+ t.pattern = 'test/**/*_test.rb'
18
+ t.verbose = true
19
+ end
20
+
21
+ desc 'Generate documentation for the has_emails plugin.'
22
+ Rake::RDocTask.new(:rdoc) do |rdoc|
23
+ rdoc.rdoc_dir = 'rdoc'
24
+ rdoc.title = 'HasEmails'
25
+ rdoc.options << '--line-numbers' << '--inline-source'
26
+ rdoc.rdoc_files.include('README')
27
+ rdoc.rdoc_files.include('lib/**/*.rb')
28
+ end
29
+
30
+ spec = Gem::Specification.new do |s|
31
+ s.name = PKG_NAME
32
+ s.version = PKG_VERSION
33
+ s.platform = Gem::Platform::RUBY
34
+ s.summary = 'Adds support for emailing capabilities between ActiveRecord models.'
35
+
36
+ s.files = FileList['{app,db,lib,test}/**/*'].to_a + %w(CHANGELOG init.rb MIT-LICENSE Rakefile README)
37
+ s.require_path = 'lib'
38
+ s.autorequire = 'has_emails'
39
+ s.has_rdoc = true
40
+ s.test_files = Dir['test/**/*_test.rb']
41
+ s.add_dependency 'has_messages', '>= 0.0.1'
42
+ s.add_dependency 'validates_as_email_address', '>= 0.0.1'
43
+
44
+ s.author = 'Aaron Pfeifer, Neil Abraham'
45
+ s.email = 'info@pluginaweek.org'
46
+ s.homepage = 'http://www.pluginaweek.org'
47
+ end
48
+
49
+ Rake::GemPackageTask.new(spec) do |p|
50
+ p.gem_spec = spec
51
+ p.need_tar = true
52
+ p.need_zip = true
53
+ end
54
+
55
+ desc 'Publish the beta gem'
56
+ task :pgem => [:package] do
57
+ Rake::SshFilePublisher.new('pluginaweek@pluginaweek.org', '/home/pluginaweek/gems.pluginaweek.org/gems', 'pkg', "#{PKG_FILE_NAME}.gem").upload
58
+ end
59
+
60
+ desc 'Publish the API documentation'
61
+ task :pdoc => [:rdoc] do
62
+ Rake::SshDirPublisher.new('pluginaweek@pluginaweek.org', "/home/pluginaweek/api.pluginaweek.org/#{PKG_NAME}", 'rdoc').upload
63
+ end
64
+
65
+ desc 'Publish the API docs and gem'
66
+ task :publish => [:pdoc, :release]
67
+
68
+ desc 'Publish the release files to RubyForge.'
69
+ task :release => [:gem, :package] do
70
+ require 'rubyforge'
71
+
72
+ ruby_forge = RubyForge.new
73
+ ruby_forge.login
74
+
75
+ %w( gem tgz zip ).each do |ext|
76
+ file = "pkg/#{PKG_FILE_NAME}.#{ext}"
77
+ puts "Releasing #{File.basename(file)}..."
78
+
79
+ ruby_forge.add_release(RUBY_FORGE_PROJECT, PKG_NAME, PKG_VERSION, file)
80
+ end
81
+ end
@@ -0,0 +1,85 @@
1
+ # Provides base operations for emailing
2
+ class ApplicationMailer < ActionMailer::Base
3
+ @@default_subject_prefix = "[#{File.basename(File.expand_path(RAILS_ROOT)).camelize}] "
4
+ cattr_accessor :default_subject_prefix
5
+
6
+ # Specify the prefix to use for the subject. This defaults to the
7
+ # +default_subject_prefix+ specified for ApplicationMailer.
8
+ adv_attr_accessor :subject_prefix
9
+
10
+ class << self
11
+ def method_missing(method_symbol, *parameters) #:nodoc:
12
+ case method_symbol.id2name
13
+ when /^queue_([_a-z]\w*)/ then new($1, *parameters).queue
14
+ else super
15
+ end
16
+ end
17
+ end
18
+
19
+ alias_method :to, :recipients
20
+
21
+ # Sets or gets the subject of the email. All subjects are prefixed with a
22
+ # value indicating the application it is coming from.
23
+ def subject(*parameters)
24
+ if parameters.empty?
25
+ super
26
+ else
27
+ super(subject_prefix + super)
28
+ end
29
+ end
30
+ alias_method :subject=, :subject
31
+
32
+ # Delivers an email based on the content in the specified email
33
+ def email(email)
34
+ @from = email.sender
35
+ @recipients = email.to
36
+ @cc = email.cc
37
+ @bcc = email.bcc
38
+ @subject = email.subject
39
+ @body = email.body
40
+ @sent_on = email.sent_at || Time.now
41
+ end
42
+
43
+ # Queues the current e-mail that has been constructed
44
+ def queue
45
+ Email.transaction do
46
+ # Create the main email
47
+ email = Email.create!(
48
+ :sender => from,
49
+ :subject => subject,
50
+ :body => body
51
+ )
52
+
53
+ # Add recipients
54
+ email.to = [to].flatten
55
+ email.cc = [cc].flatten
56
+ email.bcc = [bcc].flatten
57
+ email.queue!
58
+ end
59
+ end
60
+
61
+ private
62
+ def initialize_defaults(method_name) #:nodoc
63
+ @sent_on ||= Time.now
64
+ @subject_prefix ||= @@default_subject_prefix.dup
65
+ @recipients ||= []
66
+ @cc ||= []
67
+ @bcc ||= []
68
+
69
+ super
70
+ end
71
+
72
+ def quote_address_if_necessary_with_conversion(address, charset) #:nodoc
73
+ # Uses is_a? instead of === because of AssociationProxy
74
+ if !address.is_a?(Array)
75
+ if EmailAddress === address || EmailRecipient === address
76
+ address = address.with_name
77
+ elsif !(String === address)
78
+ address = EmailAddress.convert_from(address).to_s
79
+ end
80
+ end
81
+
82
+ quote_address_if_necessary_without_conversion(address, charset)
83
+ end
84
+ alias_method_chain :quote_address_if_necessary, :conversion
85
+ end
@@ -0,0 +1,84 @@
1
+ # Represents an email which has been sent to one or more recipients. This is
2
+ # essentially the same as the Message class, but overrides the +to+, +cc+, and +bcc+
3
+ # associations to that proper instances of the MessageRecipient class are created.
4
+ class Email < Message
5
+ validates_presence_of :sender_spec
6
+ validates_as_email_address :sender_spec,
7
+ :allow_nil => true
8
+
9
+ with_options(
10
+ :class_name => 'EmailRecipient',
11
+ :foreign_key => 'message_id',
12
+ :order => 'position ASC',
13
+ :dependent => true
14
+ ) do |e|
15
+ e.has_many :to,
16
+ :conditions => ['kind = ?', 'to'],
17
+ :extend => [MessageRecipientToBuildExtension, EmailRecipientBuildExtension]
18
+ e.has_many :cc,
19
+ :conditions => ['kind = ?', 'cc'],
20
+ :extend => [MessageRecipientCcBuildExtension, EmailRecipientBuildExtension]
21
+ e.has_many :bcc,
22
+ :conditions => ['kind = ?', 'bcc'],
23
+ :extend => [MessageRecipientBccBuildExtension, EmailRecipientBuildExtension]
24
+ end
25
+
26
+ # Returns the sender of the message. This can be a string if being sent
27
+ # from an arbitrary e-mail address.
28
+ def sender_with_spec
29
+ sender_without_spec || sender_spec
30
+ end
31
+ alias_method_chain :sender, :spec
32
+
33
+ # If sender is a string, then sets the spec, otherwise uses the original
34
+ # sender setter
35
+ def sender_with_spec=(value)
36
+ self.sender_spec = EmailAddress.convert_from(value).spec
37
+ self.sender_without_spec = value if !value.is_a?(String)
38
+ end
39
+ alias_method_chain :sender=, :spec
40
+
41
+ # Converts the sender into an Email Address, whether it be a string,
42
+ # EmailAddress, or other model type
43
+ def sender_email_address
44
+ EmailAddress.convert_from(sender_spec)
45
+ end
46
+
47
+ # The name of the person whose sending the email
48
+ def sender_name
49
+ sender_without_spec ? EmailAddress.convert_from(sender_without_spec).name : sender_email_address.name
50
+ end
51
+
52
+ # Returns a string version of the email address plus any name like
53
+ # "John Doe <john.doe@gmail.com>"..
54
+ def sender_with_name
55
+ address = self.email_address
56
+ address.name = self.name
57
+ address.with_name
58
+ end
59
+
60
+ # Actually delivers the email to the recipients
61
+ def deliver
62
+ ApplicationMailer.deliver_email(self)
63
+ end
64
+
65
+ # Saves the +sender_spec+ in the forwarded message
66
+ def forward
67
+ message = super
68
+ message.sender_spec = sender_spec
69
+ message
70
+ end
71
+
72
+ # Saves the +sender_spec+ in the replied message
73
+ def reply
74
+ message = super
75
+ message.sender_spec = sender_spec
76
+ message
77
+ end
78
+
79
+ private
80
+ # Strings are allowed to participate in messaging
81
+ def model_participant?
82
+ sender_id && sender_type || sender_spec.nil?
83
+ end
84
+ end
@@ -0,0 +1,123 @@
1
+ # Represents a valid RFC822 email address
2
+ class EmailAddress < ActiveRecord::Base
3
+ class << self
4
+ # Converts the specified record to an EmailAddress. It will convert the
5
+ # following types:
6
+ # 1. String
7
+ # 2. A record with an +email_address+ String attribute
8
+ # 3. A record with an +email_address+ association
9
+ # 4. A record with an +email_addresses+ association (first record will be chosen)
10
+ #
11
+ # If an EmailAddress is specified, the same model will be returned. An
12
+ # ArgumentError is raised if it doesn't match any of the above criteria.
13
+ def convert_from(record)
14
+ if record
15
+ if EmailAddress === record
16
+ record
17
+ elsif String === record
18
+ EmailAddress.new(:spec => record)
19
+ elsif record.respond_to?(:email_address)
20
+ if record.email_address.is_a?(String)
21
+ address = EmailAddress.new(:spec => record.email_address)
22
+ address.name = record.name if record.respond_to?(:name)
23
+ address
24
+ else
25
+ record.email_address
26
+ end
27
+ elsif record.respond_to?(:email_addresses)
28
+ record.email_addresses.first
29
+ else
30
+ raise ArgumentError, "Cannot convert #{record.class} to an EmailAddress"
31
+ end
32
+ end
33
+ end
34
+
35
+ # Determines if the given spec is a valid address using the RFC822 spec
36
+ def valid?(spec)
37
+ !RFC822::EmailAddress.match(spec).nil?
38
+ end
39
+ end
40
+
41
+ acts_as_tokenized :token_field => 'verification_code', :token_length => 32
42
+
43
+ # Support e-mail address verification
44
+ has_states :initial => :unverified
45
+
46
+ # Add messaging capabilities. This will give us an email_box.
47
+ has_messages :emails,
48
+ :message_class => 'Email'
49
+ belongs_to :emailable,
50
+ :polymorphic => true
51
+
52
+ validates_presence_of :spec
53
+
54
+ with_options(:allow_nil => true) do |klass|
55
+ klass.validates_uniqueness_of :spec
56
+ klass.validates_as_email_address :spec
57
+ end
58
+
59
+ # The name of the person who owns this email address
60
+ attr_accessor :name
61
+
62
+ # Ensure that the e-mail address has a verification code that can be sent
63
+ # to the user
64
+ before_create :set_code_expiry
65
+
66
+ state :unverified, :verified
67
+
68
+ # Verifies that the email address is valid
69
+ event :verify do
70
+ transition_to :verified, :from => :unverified
71
+ end
72
+
73
+ # Sets the full address
74
+ def spec=(new_spec)
75
+ @local_name = @domain = nil
76
+ write_attribute(:spec, new_spec)
77
+ end
78
+
79
+ # The part of the e-mail address before the @
80
+ def local_name
81
+ parse_spec if !@local_name
82
+ @local_name
83
+ end
84
+
85
+ # The part of the e-mail address after the @
86
+ def domain
87
+ parse_spec if !@domain
88
+ @domain
89
+ end
90
+
91
+ # Gets the name of the person whose email address this is. Default is an
92
+ # empty string. Override this if you want it to appear in with_name
93
+ def name
94
+ @name || ''
95
+ end
96
+
97
+ # Returns a string version of the email address plus any name like
98
+ # "John Doe <john.doe@gmail.com>". In order to have a valid name within the
99
+ # string, you must override +name+.
100
+ def with_name
101
+ name.blank? ? to_s : "#{name} <#{to_s}>"
102
+ end
103
+
104
+ # Returns the full email address (without the name)
105
+ def to_s #:nodoc
106
+ spec
107
+ end
108
+
109
+ private
110
+ # Sets the time at which the verification code will expire
111
+ def set_code_expiry
112
+ self.code_expiry = 48.hour.from_now
113
+ end
114
+
115
+ # Parses the current spec and sets +@local_name+ and +@domain+ based on the
116
+ # matching groups within the regular expression
117
+ def parse_spec
118
+ if !@local_name && !@domain && match = RFC822::EmailAddress.match(spec)
119
+ @local_name = match.captures[0]
120
+ @domain = match.captures[1]
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,78 @@
1
+ # Represents a recipient on an email
2
+ class EmailRecipient < MessageRecipient
3
+ validates_presence_of :receiver_spec
4
+ validates_as_email_address :receiver_spec,
5
+ :allow_nil => true
6
+
7
+ before_save :ensure_exclusive_references
8
+
9
+ # Alias for domain-specific language
10
+ alias_method :email, :message
11
+ alias_method :email=, :message=
12
+ alias_attribute :email_id, :message_id
13
+
14
+ delegate :to_s,
15
+ :to => :email_address
16
+
17
+ # Returns the receiver of the message. This can be a string if being sent
18
+ # to an arbitrary e-mail address.
19
+ def receiver_with_spec
20
+ receiver_without_spec || receiver_spec
21
+ end
22
+ alias_method_chain :receiver, :spec
23
+
24
+ # If receiver is a string, then sets the spec, otherwise uses the original
25
+ # receiver setter
26
+ def receiver_with_spec=(value)
27
+ self.receiver_spec = EmailAddress.convert_from(value).spec
28
+ self.receiver_without_spec = value if !value.is_a?(String)
29
+ end
30
+ alias_method_chain :receiver=, :spec
31
+
32
+ # Converts the receiver into an Email Address, whether it be a string,
33
+ # EmailAddress, or other model type
34
+ def email_address
35
+ EmailAddress.convert_from(receiver_spec)
36
+ end
37
+
38
+ # The name of the person whose receiving the email
39
+ def name
40
+ receiver_without_spec ? EmailAddress.convert_from(receiver_without_spec).name : email_address.name
41
+ end
42
+
43
+ # Returns a string version of the email address plus any name like
44
+ # "John Doe <john.doe@gmail.com>"..
45
+ def with_name
46
+ address = self.email_address
47
+ address.name = self.name
48
+ address.with_name
49
+ end
50
+
51
+ private
52
+ def validate_on_create #:nodoc:
53
+ begin
54
+ email_address if receiver
55
+ true
56
+ rescue ArgumentError
57
+ errors.add 'receiver_id', 'must be a string, have a email_address attribute, or be a class that has_email_addresses'
58
+ end
59
+ end
60
+
61
+ # Strings are allowed to participate in messaging
62
+ def model_participant?
63
+ receiver_id && receiver_type || receiver_spec.nil?
64
+ end
65
+
66
+ # Ensures that the country id/user region combo is not set at the same time as
67
+ # the region id
68
+ def ensure_exclusive_references
69
+ if model_participant?
70
+ self.receiver_spec = nil
71
+ else
72
+ self.receiver_id = nil
73
+ self.receiver_type = nil
74
+ end
75
+
76
+ true
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ module EmailRecipientBuildExtension #:nodoc:
2
+ # Checks if the recipient and record are equal, using the recipient's
3
+ # email_address
4
+ def is_recipient_equal?(recipient, record) #:nodoc:
5
+ recipient.email_address.to_s == EmailAddress.convert_from(record).to_s
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ verify:
2
+ id: 601
3
+ name: verify
4
+ owner_type: EmailAddress
@@ -0,0 +1,9 @@
1
+ unverified:
2
+ id: 601
3
+ name: unverified
4
+ owner_type: EmailAddress
5
+
6
+ verified:
7
+ id: 602
8
+ name: verified
9
+ owner_type: EmailAddress
@@ -0,0 +1,23 @@
1
+ class CreateEmailAddresses < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :email_addresses do |t|
4
+ t.column :emailable_id, :integer, :null => false, :references => nil
5
+ t.column :emailable_type, :string, :null => false
6
+ t.column :spec, :string, :null => false, :limit => 382
7
+ t.column :verification_code, :string, :limit => 40
8
+ t.column :code_expiry, :datetime
9
+ t.column :created_at, :timestamp, :null => false
10
+ t.column :updated_at, :datetime, :null => false
11
+ end
12
+ add_index :email_addresses, :spec, :unique => true
13
+ add_index :email_addresses, :verification_code, :unique => true
14
+
15
+ PluginAWeek::Has::States.migrate_up(:email_addresses)
16
+ end
17
+
18
+ def self.down
19
+ PluginAWeek::Has::States.migrate_down(:email_addresses)
20
+
21
+ drop_table :email_addresses
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ class AddEmailSpecs < ActiveRecord::Migration
2
+ def self.up
3
+ # Workaround change_column not allowing change to :null => true
4
+ remove_column :messages, :sender_id
5
+ remove_column :messages, :sender_type
6
+
7
+ add_column :messages, :sender_id, :integer, :null => true, :default => nil, :references => nil
8
+ add_column :messages, :sender_type, :string, :null => true, :default => nil
9
+ add_column :messages, :sender_spec, :string, :limit => 320
10
+ end
11
+
12
+ def self.down
13
+ remove_column :messages, :sender_spec
14
+
15
+ change_column :messages, :sender_id, :integer, :null => false, :references => nil
16
+ change_column :messages, :sender_type, :string, :null => false
17
+ end
18
+ end