Commit f3f04a53c45d39468b43272d6da7b2666e12935f
Committed by
Antonio Terceiro
1 parent
3d351025
Exists in
staging
and in
42 other branches
ActionItem791: re-implement contact-us without tasks
- add fields city and state to contact form - aceess_control plugin: filter members by role - stay on contact form after send message - validates format of email only if filled - remove phone and add name and fill fields if user logged in - mark contact fields to translation
Showing
21 changed files
with
394 additions
and
74 deletions
Show diff stats
app/controllers/public/contact_controller.rb
| @@ -3,14 +3,24 @@ class ContactController < PublicController | @@ -3,14 +3,24 @@ class ContactController < PublicController | ||
| 3 | needs_profile | 3 | needs_profile |
| 4 | 4 | ||
| 5 | def new | 5 | def new |
| 6 | - @contact = Contact.new(params[:contact]) | 6 | + @contact |
| 7 | if request.post? | 7 | if request.post? |
| 8 | - if @contact.save | 8 | + @contact = Contact.new(params[:contact]) |
| 9 | + @contact.dest = profile | ||
| 10 | + @contact.city = City.exists?(params[:city]) ? City.find(params[:city]).name : _('Missing') | ||
| 11 | + @contact.state = State.exists?(params[:state]) ? State.find(params[:state]).name : _('Missing') | ||
| 12 | + if @contact.deliver | ||
| 9 | flash[:notice] = _('Contact successfully sent') | 13 | flash[:notice] = _('Contact successfully sent') |
| 10 | - redirect_to :controller => 'profile', :profile => profile.identifier | 14 | + redirect_to :action => 'new' |
| 11 | else | 15 | else |
| 12 | flash[:notice] = _('Contact not sent') | 16 | flash[:notice] = _('Contact not sent') |
| 13 | end | 17 | end |
| 18 | + else | ||
| 19 | + if logged_in? | ||
| 20 | + @contact = Contact.new(:name => user.name, :email => user.email) | ||
| 21 | + else | ||
| 22 | + @contact = Contact.new | ||
| 23 | + end | ||
| 14 | end | 24 | end |
| 15 | end | 25 | end |
| 16 | 26 |
app/models/contact.rb
| 1 | -class Contact < Task | 1 | +class Contact < ActiveRecord::Base #WithoutTable |
| 2 | + tableless :columns => [ | ||
| 3 | + [:name, :string], | ||
| 4 | + [:subject, :string], | ||
| 5 | + [:message, :string], | ||
| 6 | + [:email, :string], | ||
| 7 | + [:state, :string], | ||
| 8 | + [:city, :string] | ||
| 9 | + ] | ||
| 10 | + attr_accessor :dest | ||
| 2 | 11 | ||
| 3 | - validates_presence_of :target_id, :subject, :email, :message | ||
| 4 | - validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT | 12 | + N_('Subject'); N_('Message'); N_('City and state'); N_('e-Mail'); N_('Name') |
| 5 | 13 | ||
| 6 | - acts_as_having_settings :field => :data | ||
| 7 | - settings_items :subject, :message, :city_and_state, :email, :phone | 14 | + validates_presence_of :subject, :email, :message, :name |
| 15 | + validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|o| !o.email.blank?}) | ||
| 8 | 16 | ||
| 9 | - def description | ||
| 10 | - _('%s sent a new message') % (requestor ? requestor.name : _('Someone')) | 17 | + def deliver |
| 18 | + Contact::Sender.deliver_mail(self) | ||
| 19 | + end | ||
| 20 | + | ||
| 21 | + class Sender < ActionMailer::Base | ||
| 22 | + def mail(contact) | ||
| 23 | + emails = [contact.dest.contact_email] + contact.dest.admins.map{|i| i.email} | ||
| 24 | + recipients emails | ||
| 25 | + from "#{contact.name} <#{contact.email}>" | ||
| 26 | + subject contact.subject | ||
| 27 | + body :name => contact.name, | ||
| 28 | + :email => contact.email, | ||
| 29 | + :city => contact.city, | ||
| 30 | + :state => contact.state, | ||
| 31 | + :message => contact.message, | ||
| 32 | + :environment => contact.dest.environment.name, | ||
| 33 | + :url => url_for(:host => contact.dest.environment.default_hostname, :controller => 'home') | ||
| 34 | + end | ||
| 11 | end | 35 | end |
| 12 | 36 | ||
| 13 | end | 37 | end |
app/models/profile.rb
| @@ -514,4 +514,8 @@ class Profile < ActiveRecord::Base | @@ -514,4 +514,8 @@ class Profile < ActiveRecord::Base | ||
| 514 | !self.articles.count(:conditions => {:type => 'Blog'}).zero? | 514 | !self.articles.count(:conditions => {:type => 'Blog'}).zero? |
| 515 | end | 515 | end |
| 516 | 516 | ||
| 517 | + def admins | ||
| 518 | + self.members_by_role(Profile::Roles.admin) | ||
| 519 | + end | ||
| 520 | + | ||
| 517 | end | 521 | end |
app/views/contact/new.rhtml
| @@ -4,13 +4,11 @@ | @@ -4,13 +4,11 @@ | ||
| 4 | 4 | ||
| 5 | <% labelled_form_for :contact, @contact do |f| %> | 5 | <% labelled_form_for :contact, @contact do |f| %> |
| 6 | 6 | ||
| 7 | - <%= hidden_field_tag 'contact[target_id]', profile.id %> | ||
| 8 | - <%= hidden_field_tag 'contact[requestor_id]', (logged_in? ? current_user.person.id : nil) %> | ||
| 9 | - <%= required f.text_field(:subject) %> | ||
| 10 | - <%= required f.text_field(:email) %> | ||
| 11 | - <%= f.text_field :city_and_state %> | ||
| 12 | - <%= f.text_field :phone %> | ||
| 13 | - <%= required f.text_area(:message, :rows => 5) %> | 7 | + <%= f.text_field :name %> |
| 8 | + <%= f.text_field :email %> | ||
| 9 | + <%= labelled_form_field _('City and state'), select_city(true) %> | ||
| 10 | + <%= f.text_field :subject %> | ||
| 11 | + <%= f.text_area :message, :rows => 10, :cols => 60 %> | ||
| 14 | 12 | ||
| 15 | <%= submit_button(:send, _('Send')) %> | 13 | <%= submit_button(:send, _('Send')) %> |
| 16 | 14 |
app/views/tasks/_contact.rhtml
| @@ -1,18 +0,0 @@ | @@ -1,18 +0,0 @@ | ||
| 1 | -<h2><%= task.description %></h2> | ||
| 2 | - | ||
| 3 | -<% form_for('task', task, :url => { :action => 'close', :id => task.id}) do |f| %> | ||
| 4 | - | ||
| 5 | - <%= hidden_field_tag(:decision, :finish) %> | ||
| 6 | - <table> | ||
| 7 | - <% %w[ subject email phone city_and_state message ].each do |field| %> | ||
| 8 | - <% if task.respond_to?(field) and !task.send(field).nil? and !task.send(field).empty? %> | ||
| 9 | - <tr> <td><strong><%= _(field.humanize) %></strong></td> <td><%= task.send(field) %></td> </tr> | ||
| 10 | - <% end %> | ||
| 11 | - <% end %> | ||
| 12 | - </table> | ||
| 13 | - | ||
| 14 | - <% button_bar do %> | ||
| 15 | - <%= submit_button(:ok, _('Ok!')) %> | ||
| 16 | - <% end %> | ||
| 17 | - | ||
| 18 | -<% end %> |
test/functional/contact_controller_test.rb
| @@ -43,33 +43,30 @@ class ContactControllerTest < Test::Unit::TestCase | @@ -43,33 +43,30 @@ class ContactControllerTest < Test::Unit::TestCase | ||
| 43 | assert_tag :tag => 'textarea', :attributes => { :name => 'contact[message]' } | 43 | assert_tag :tag => 'textarea', :attributes => { :name => 'contact[message]' } |
| 44 | end | 44 | end |
| 45 | 45 | ||
| 46 | - should 'add hidden field with target_id' do | ||
| 47 | - get :new, :profile => enterprise.identifier | ||
| 48 | - assert_tag :tag => 'input', :attributes => { :name => 'contact[target_id]', :value => enterprise.id, :type => 'hidden' } | 46 | + should 'redirect back to contact page after send contact' do |
| 47 | + post :new, :profile => enterprise.identifier, :contact => {:name => 'john', :subject => 'Hi', :email => 'visitor@mail.invalid', :message => 'Hi, all'} | ||
| 48 | + assert_response :redirect | ||
| 49 | + assert_redirected_to :action => 'new' | ||
| 49 | end | 50 | end |
| 50 | 51 | ||
| 51 | - should 'add requestor id if logged in' do | 52 | + should 'fill email if user logged in' do |
| 52 | login_as(profile.identifier) | 53 | login_as(profile.identifier) |
| 53 | - @controller.stubs(:current_user).returns(profile.user) | ||
| 54 | get :new, :profile => enterprise.identifier | 54 | get :new, :profile => enterprise.identifier |
| 55 | - assert_tag :tag => 'input', :attributes => { :name => 'contact[requestor_id]', :value => profile.id } | 55 | + assert_tag :tag => 'input', :attributes => {:name => 'contact[email]', :value => profile.email} |
| 56 | end | 56 | end |
| 57 | 57 | ||
| 58 | - should 'nil requestor id if not logged in' do | 58 | + should 'fill name if user logged in' do |
| 59 | + login_as(profile.identifier) | ||
| 59 | get :new, :profile => enterprise.identifier | 60 | get :new, :profile => enterprise.identifier |
| 60 | - assert_tag :tag => 'input', :attributes => { :name => 'contact[requestor_id]', :value => nil } | ||
| 61 | - end | ||
| 62 | - | ||
| 63 | - should 'redirect to profile page after contact' do | ||
| 64 | - post :new, :profile => enterprise.identifier, :contact => {:subject => 'Hi', :email => 'visitor@mail.invalid', :message => 'Hi, all', :target_id => enterprise.id} | ||
| 65 | - assert_response :redirect | ||
| 66 | - assert_redirected_to :controller => 'profile', :profile => enterprise.identifier | 61 | + assert_tag :tag => 'input', :attributes => {:name => 'contact[name]', :value => profile.name} |
| 67 | end | 62 | end |
| 68 | 63 | ||
| 69 | - should 'be able to send contact' do | ||
| 70 | - assert_difference Contact, :count do | ||
| 71 | - post :new, :profile => enterprise.identifier, :contact => {:subject => 'Hi', :email => 'visitor@mail.invalid', :message => 'Hi, all', :target_id => enterprise.id} | ||
| 72 | - end | 64 | + should 'define city and state' do |
| 65 | + City.stubs(:find).returns(City.new(:name => 'Camaçari')) | ||
| 66 | + State.stubs(:find).returns(State.new(:name => 'Bahia')) | ||
| 67 | + post :new, :profile => enterprise.identifier, :contact => {:name => 'john', :subject => 'Hi', :email => 'visitor@mail.invalid', :message => 'Hi, all', :state => 1, :city => 1} | ||
| 68 | + assert_equal 'Camaçari', assigns(:contact).city | ||
| 69 | + assert_equal 'Bahia', assigns(:contact).state | ||
| 73 | end | 70 | end |
| 74 | 71 | ||
| 75 | end | 72 | end |
test/functional/tasks_controller_test.rb
| @@ -152,15 +152,4 @@ class TasksControllerTest < Test::Unit::TestCase | @@ -152,15 +152,4 @@ class TasksControllerTest < Test::Unit::TestCase | ||
| 152 | assert_equal f, assigns(:ticket).target | 152 | assert_equal f, assigns(:ticket).target |
| 153 | end | 153 | end |
| 154 | 154 | ||
| 155 | - should 'list enterprise contacts' do | ||
| 156 | - ent = Enterprise.create!(:identifier => 'contact_test_enterprise', :name => 'Test contact enteprise') | ||
| 157 | - task = Contact.create!(:subject => 'test', :target_id => profile.id, :email => 'visitor@invalid.com', :message => 'Hi, all') | ||
| 158 | - | ||
| 159 | - login_as(profile.identifier) | ||
| 160 | - get :index, :profile => ent.identifier | ||
| 161 | - | ||
| 162 | - assert_includes assigns(:tasks), task | ||
| 163 | - assert_tag :tag => 'li', :attributes => { :class => 'task-Contact' }, :content => 'Someone sent a new message' | ||
| 164 | - end | ||
| 165 | - | ||
| 166 | end | 155 | end |
| @@ -0,0 +1,54 @@ | @@ -0,0 +1,54 @@ | ||
| 1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | + | ||
| 3 | +class ContactSenderTest < Test::Unit::TestCase | ||
| 4 | + FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures' | ||
| 5 | + CHARSET = "utf-8" | ||
| 6 | + | ||
| 7 | + def setup | ||
| 8 | + ActionMailer::Base.delivery_method = :test | ||
| 9 | + ActionMailer::Base.perform_deliveries = true | ||
| 10 | + ActionMailer::Base.deliveries = [] | ||
| 11 | + | ||
| 12 | + @expected = TMail::Mail.new | ||
| 13 | + @expected.set_content_type "text", "plain", { "charset" => CHARSET } | ||
| 14 | + end | ||
| 15 | + | ||
| 16 | + should 'be able to deliver mail' do | ||
| 17 | + ent = Enterprise.new(:name => 'my enterprise', :identifier => 'myent', :environment => Environment.default) | ||
| 18 | + ent.contact_email = 'contact@invalid.com' | ||
| 19 | + c = Contact.new(:dest => ent, :subject => 'hi molly') | ||
| 20 | + response = Contact::Sender.deliver_mail(c) | ||
| 21 | + assert_equal c.email, response.from | ||
| 22 | + assert_equal c.subject, response.subject | ||
| 23 | + end | ||
| 24 | + | ||
| 25 | + should 'deliver mail to contact_email' do | ||
| 26 | + ent = Enterprise.new(:name => 'my enterprise', :identifier => 'myent', :environment => Environment.default) | ||
| 27 | + ent.contact_email = 'contact@invalid.com' | ||
| 28 | + c = Contact.new(:dest => ent) | ||
| 29 | + response = Contact::Sender.deliver_mail(c) | ||
| 30 | + assert_includes response.to, c.dest.contact_email | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + should 'deliver mail to admins of enterprise' do | ||
| 34 | + admin = create_user('admin_test').person | ||
| 35 | + ent = Enterprise.create!(:name => 'my enterprise', :identifier => 'myent', :environment => Environment.default) | ||
| 36 | + ent.contact_email = 'contact@invalid.com' | ||
| 37 | + ent.add_admin(admin) | ||
| 38 | + assert ent.save! | ||
| 39 | + c = Contact.new(:dest => ent) | ||
| 40 | + response = Contact::Sender.deliver_mail(c) | ||
| 41 | + assert_includes response.to, admin.email | ||
| 42 | + end | ||
| 43 | + | ||
| 44 | + private | ||
| 45 | + | ||
| 46 | + def read_fixture(action) | ||
| 47 | + IO.readlines("#{FIXTURES_PATH}/mail_sender/#{action}") | ||
| 48 | + end | ||
| 49 | + | ||
| 50 | + def encode(subject) | ||
| 51 | + quoted_printable(subject, CHARSET) | ||
| 52 | + end | ||
| 53 | + | ||
| 54 | +end |
test/unit/contact_test.rb
| @@ -2,24 +2,39 @@ require File.dirname(__FILE__) + '/../test_helper' | @@ -2,24 +2,39 @@ require File.dirname(__FILE__) + '/../test_helper' | ||
| 2 | 2 | ||
| 3 | class ContactTest < ActiveSupport::TestCase | 3 | class ContactTest < ActiveSupport::TestCase |
| 4 | 4 | ||
| 5 | - should 'have serialized data' do | ||
| 6 | - t = Contact.new | ||
| 7 | - t.data[:test] = 'test' | ||
| 8 | - | ||
| 9 | - assert_equal({:test => 'test'}, t.data) | ||
| 10 | - end | ||
| 11 | - | ||
| 12 | should 'validates required fields' do | 5 | should 'validates required fields' do |
| 13 | contact = Contact.new | 6 | contact = Contact.new |
| 14 | assert !contact.valid? | 7 | assert !contact.valid? |
| 8 | + | ||
| 15 | contact.subject = 'Hi' | 9 | contact.subject = 'Hi' |
| 16 | assert !contact.valid? | 10 | assert !contact.valid? |
| 11 | + | ||
| 12 | + contact.name = 'john' | ||
| 13 | + assert !contact.valid? | ||
| 14 | + | ||
| 17 | contact.email = 'visitor@invalid.com' | 15 | contact.email = 'visitor@invalid.com' |
| 18 | assert !contact.valid? | 16 | assert !contact.valid? |
| 17 | + | ||
| 19 | contact.message = 'Hi, all' | 18 | contact.message = 'Hi, all' |
| 20 | - assert !contact.valid? | ||
| 21 | - contact.target = create_user('contact_user_test').person | ||
| 22 | - assert contact.save! | 19 | + assert contact.valid? |
| 20 | + end | ||
| 21 | + | ||
| 22 | + should 'validates format of email only if not empty' do | ||
| 23 | + contact = Contact.new | ||
| 24 | + contact.valid? | ||
| 25 | + assert_equal "Email can't be blank", contact.errors[:email] | ||
| 26 | + end | ||
| 27 | + | ||
| 28 | + should 'inicialize fields on instanciate' do | ||
| 29 | + assert_nothing_raised ArgumentError do | ||
| 30 | + Contact.new(:name => 'john', :email => 'contact@invalid.com') | ||
| 31 | + end | ||
| 32 | + end | ||
| 33 | + | ||
| 34 | + should 'deliver message' do | ||
| 35 | + ent = Enterprise.create!(:name => 'my enterprise', :identifier => 'myent', :environment => Environment.default) | ||
| 36 | + c = Contact.new(:name => 'john', :email => 'john@invalid.com', :subject => 'hi', :message => 'hi, all', :dest => ent) | ||
| 37 | + assert c.deliver | ||
| 23 | end | 38 | end |
| 24 | 39 | ||
| 25 | end | 40 | end |
test/unit/profile_test.rb
| @@ -1112,6 +1112,14 @@ class ProfileTest < Test::Unit::TestCase | @@ -1112,6 +1112,14 @@ class ProfileTest < Test::Unit::TestCase | ||
| 1112 | assert_nil p.blog | 1112 | assert_nil p.blog |
| 1113 | end | 1113 | end |
| 1114 | 1114 | ||
| 1115 | + should 'list admins' do | ||
| 1116 | + c = Profile.create!(:name => 'my test profile', :identifier => 'mytestprofile') | ||
| 1117 | + p = create_user('mytestuser').person | ||
| 1118 | + c.add_admin(p) | ||
| 1119 | + | ||
| 1120 | + assert_equal [p], c.admins | ||
| 1121 | + end | ||
| 1122 | + | ||
| 1115 | private | 1123 | private |
| 1116 | 1124 | ||
| 1117 | def assert_invalid_identifier(id) | 1125 | def assert_invalid_identifier(id) |
vendor/plugins/access_control/lib/acts_as_accessible.rb
| @@ -27,6 +27,9 @@ class ActiveRecord::Base | @@ -27,6 +27,9 @@ class ActiveRecord::Base | ||
| 27 | def members | 27 | def members |
| 28 | role_assignments.map(&:accessor).uniq | 28 | role_assignments.map(&:accessor).uniq |
| 29 | end | 29 | end |
| 30 | + def members_by_role(role) | ||
| 31 | + role_assignments.select{|i| i.role.key == role.key}.map(&:accessor).uniq | ||
| 32 | + end | ||
| 30 | 33 | ||
| 31 | def roles | 34 | def roles |
| 32 | Role.find(:all).select do |r| | 35 | Role.find(:all).select do |r| |
vendor/plugins/access_control/test/acts_as_accessor_test.rb
| @@ -55,4 +55,13 @@ class ActAsAccessorTest < Test::Unit::TestCase | @@ -55,4 +55,13 @@ class ActAsAccessorTest < Test::Unit::TestCase | ||
| 55 | assert !a.role_assignments.map{|ra|[ra.role, ra.accessor, ra.resource]}.include?([role, a, res]) | 55 | assert !a.role_assignments.map{|ra|[ra.role, ra.accessor, ra.resource]}.include?([role, a, res]) |
| 56 | assert !a.remove_role(role, res) | 56 | assert !a.remove_role(role, res) |
| 57 | end | 57 | end |
| 58 | + | ||
| 59 | + def test_get_members_by_role | ||
| 60 | + res = AccessControlTestResource.create!(:name => 'bla') | ||
| 61 | + a = AccessControlTestAccessor.create!(:name => 'ze') | ||
| 62 | + role = Role.create!(:name => 'another_content_author', :permissions => ['bli']) | ||
| 63 | + assert a.add_role(role, res) | ||
| 64 | + assert_equal [a], a.members_by_role(role) | ||
| 65 | + end | ||
| 66 | + | ||
| 58 | end | 67 | end |
| @@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
| 1 | +Copyright (c) 2008 [name of plugin creator] | ||
| 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. |
| @@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
| 1 | +ActiveRecordTableless | ||
| 2 | +===================== | ||
| 3 | + | ||
| 4 | +Rails plugin allowing ActiveRecord models to be used with validations but | ||
| 5 | +without being backed by a database table. | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +Install | ||
| 9 | +======= | ||
| 10 | + | ||
| 11 | +script/plugin install git://github.com/robinsp/active_record_tableless.git | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +Example | ||
| 15 | +======= | ||
| 16 | + | ||
| 17 | +class TablelessModel < ActiveRecord::Base | ||
| 18 | + tableless :columns => [ | ||
| 19 | + [:email, :string], | ||
| 20 | + [:password, :string], | ||
| 21 | + [:password_confirmation] | ||
| 22 | + ] | ||
| 23 | + | ||
| 24 | + validates_presence_of :email, :password, :password_confirmation | ||
| 25 | + validates_confirmation_of :password | ||
| 26 | + | ||
| 27 | +end | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +Copyright (c) 2008 [name of plugin creator], released under the MIT license |
| @@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
| 1 | +require 'rake' | ||
| 2 | +require 'rake/testtask' | ||
| 3 | +require 'rake/rdoctask' | ||
| 4 | + | ||
| 5 | +desc 'Default: run unit tests.' | ||
| 6 | +task :default => :test | ||
| 7 | + | ||
| 8 | +desc 'Test the active_record_tableless plugin.' | ||
| 9 | +Rake::TestTask.new(:test) do |t| | ||
| 10 | + t.libs << 'lib' | ||
| 11 | + t.pattern = 'test/**/*_test.rb' | ||
| 12 | + t.verbose = true | ||
| 13 | +end | ||
| 14 | + | ||
| 15 | +desc 'Generate documentation for the active_record_tableless plugin.' | ||
| 16 | +Rake::RDocTask.new(:rdoc) do |rdoc| | ||
| 17 | + rdoc.rdoc_dir = 'rdoc' | ||
| 18 | + rdoc.title = 'ActiveRecordTableless' | ||
| 19 | + rdoc.options << '--line-numbers' << '--inline-source' | ||
| 20 | + rdoc.rdoc_files.include('README') | ||
| 21 | + rdoc.rdoc_files.include('lib/**/*.rb') | ||
| 22 | +end |
vendor/plugins/active_record_tableless/lib/active_record/tableless.rb
0 → 100644
| @@ -0,0 +1,56 @@ | @@ -0,0 +1,56 @@ | ||
| 1 | +module ActiveRecord | ||
| 2 | + module Tableless | ||
| 3 | + | ||
| 4 | + def self.included(base) | ||
| 5 | + # 'base' is assumed to be ActiveRecord::Base | ||
| 6 | + base.extend(ClassMethods) | ||
| 7 | + end | ||
| 8 | + | ||
| 9 | + module ClassMethods | ||
| 10 | + def tableless( options = {} ) | ||
| 11 | + include ActiveRecord::Tableless::InstanceMethods | ||
| 12 | + raise "No columns defined" unless options.has_key?(:columns) && !options[:columns].empty? | ||
| 13 | + | ||
| 14 | + self.extend(MetaMethods) | ||
| 15 | + | ||
| 16 | + for column_args in options[:columns] | ||
| 17 | + column( *column_args ) | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + end | ||
| 21 | + end | ||
| 22 | + | ||
| 23 | + module MetaMethods | ||
| 24 | + def columns() | ||
| 25 | + @columns ||= [] | ||
| 26 | + end | ||
| 27 | + | ||
| 28 | + def column(name, sql_type = nil, default = nil, null = true) | ||
| 29 | + columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) | ||
| 30 | + reset_column_information | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + # Do not reset @columns | ||
| 34 | + def reset_column_information | ||
| 35 | + generated_methods.each { |name| undef_method(name) } | ||
| 36 | + @column_names = @columns_hash = @content_columns = @dynamic_methods_hash = @read_methods = nil | ||
| 37 | + end | ||
| 38 | + end | ||
| 39 | + | ||
| 40 | + module InstanceMethods | ||
| 41 | + def create_or_update | ||
| 42 | + errors.empty? | ||
| 43 | + end | ||
| 44 | + | ||
| 45 | + def saved!(with_id = 1) | ||
| 46 | + self.id = with_id | ||
| 47 | + | ||
| 48 | + def self.new_record? | ||
| 49 | + false | ||
| 50 | + end | ||
| 51 | + end | ||
| 52 | + alias_method :exists!, :saved! | ||
| 53 | + end | ||
| 54 | + | ||
| 55 | + end | ||
| 56 | +end | ||
| 0 | \ No newline at end of file | 57 | \ No newline at end of file |
vendor/plugins/active_record_tableless/tasks/active_record_tableless_tasks.rake
0 → 100644
vendor/plugins/active_record_tableless/test/active_record_tableless_test.rb
0 → 100644
| @@ -0,0 +1,75 @@ | @@ -0,0 +1,75 @@ | ||
| 1 | +require 'test/unit' | ||
| 2 | +require 'rubygems' | ||
| 3 | +require 'active_record' | ||
| 4 | +require File.dirname(__FILE__) + '/../lib/active_record/tableless' | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +ActiveRecord::Base.establish_connection( { | ||
| 9 | + :adapter => 'sqlite3', | ||
| 10 | + :database => ":memory:", | ||
| 11 | + :timeout => 500 | ||
| 12 | + | ||
| 13 | +}) | ||
| 14 | + | ||
| 15 | +ActiveRecord::Base.send(:include, ActiveRecord::Tableless) | ||
| 16 | + | ||
| 17 | +class TablelessModel < ActiveRecord::Base | ||
| 18 | + tableless :columns => [ | ||
| 19 | + [:email, :string], | ||
| 20 | + [:password, :string], | ||
| 21 | + [:password_confirmation] ] | ||
| 22 | + | ||
| 23 | + validates_presence_of :email, :password, :password_confirmation | ||
| 24 | + validates_confirmation_of :password | ||
| 25 | + | ||
| 26 | +end | ||
| 27 | + | ||
| 28 | +class ActiveRecordTablelessTest < Test::Unit::TestCase | ||
| 29 | + | ||
| 30 | + def setup | ||
| 31 | + super | ||
| 32 | + @valid_attributes = { | ||
| 33 | + :email => "robin@bogus.com", | ||
| 34 | + :password => "password", | ||
| 35 | + :password_confirmation => "password" | ||
| 36 | + } | ||
| 37 | + end | ||
| 38 | + | ||
| 39 | + def test_create | ||
| 40 | + assert TablelessModel.create(@valid_attributes).valid? | ||
| 41 | + end | ||
| 42 | + | ||
| 43 | + def test_validations | ||
| 44 | + # Just check a few validations to make sure we didn't break ActiveRecord::Validations::ClassMethods | ||
| 45 | + assert_not_nil TablelessModel.create(@valid_attributes.merge(:email => "")).errors[:email] | ||
| 46 | + assert_not_nil TablelessModel.create(@valid_attributes.merge(:password => "")).errors[:password] | ||
| 47 | + assert_not_nil TablelessModel.create(@valid_attributes.merge(:password_confirmation => "")).errors[:password] | ||
| 48 | + end | ||
| 49 | + | ||
| 50 | + def test_save | ||
| 51 | + assert TablelessModel.new(@valid_attributes).save | ||
| 52 | + assert !TablelessModel.new(@valid_attributes.merge(:password => "no_match")).save | ||
| 53 | + end | ||
| 54 | + | ||
| 55 | + def test_valid? | ||
| 56 | + assert TablelessModel.new(@valid_attributes).valid? | ||
| 57 | + assert !TablelessModel.new(@valid_attributes.merge(:password => "no_match")).valid? | ||
| 58 | + end | ||
| 59 | + | ||
| 60 | + | ||
| 61 | + def test_exists! | ||
| 62 | + m = TablelessModel.new(@valid_attributes) | ||
| 63 | + | ||
| 64 | + assert_nil m.id | ||
| 65 | + assert m.new_record? | ||
| 66 | + | ||
| 67 | + m.exists! | ||
| 68 | + assert_equal 1, m.id | ||
| 69 | + assert !m.new_record? | ||
| 70 | + | ||
| 71 | + m.exists!(250) | ||
| 72 | + assert_equal 250, m.id | ||
| 73 | + assert !m.new_record? | ||
| 74 | + end | ||
| 75 | +end |