bento 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +38 -5
- data/lib/bento.rb +1 -0
- data/lib/bento/controllers/account_scopable.rb +75 -43
- data/lib/bento/models/modules/user_association.rb +2 -1
- data/lib/bento/models/user.rb +24 -0
- data/lib/bento/rails/routes.rb +7 -2
- data/lib/bento/version.rb +1 -1
- data/lib/generators/active_record/bento_generator.rb +5 -5
- data/lib/generators/active_record/templates/bento_membership_migration.rb +25 -0
- data/lib/generators/bento/orm_helpers.rb +50 -0
- data/spec/bento/models/modules/user_accessors_spec.rb +12 -2
- data/spec/bento/models/user_spec.rb +24 -0
- data/spec/controllers/bento_for_custom_routes_spec.rb +38 -0
- data/spec/controllers/bento_for_detault_routes_spec.rb +23 -0
- data/spec/controllers/bento_for_nested_routes_spec.rb +28 -0
- data/spec/rails_app/app/models/account.rb +3 -1
- data/spec/rails_app/app/models/bento_membership.rb +6 -0
- data/spec/rails_app/app/models/user.rb +8 -3
- data/spec/rails_app/app/views/layouts/application.html.erb +6 -1
- data/spec/rails_app/app/views/projects/_my_accounts.html.erb +6 -0
- data/spec/rails_app/app/views/projects/_my_projects.html.erb +9 -0
- data/spec/rails_app/app/views/projects/index.html.erb +4 -0
- data/spec/rails_app/config/environment.rb +4 -0
- data/spec/rails_app/db/development.sqlite3 +0 -0
- data/spec/rails_app/db/migrate/20101015094514_bento_create_accounts.rb +0 -1
- data/spec/rails_app/db/migrate/20110821091847_add_plan_to_accounts.rb +9 -0
- data/spec/rails_app/db/migrate/20110821095924_bento_create_bento_memberships.rb +25 -0
- data/spec/rails_app/{log/production.log → db/production.sqlite3} +0 -0
- data/spec/rails_app/db/schema.rb +11 -3
- data/spec/rails_app/db/test.sqlite3 +0 -0
- data/spec/rails_app/log/development.log +78 -72
- data/spec/rails_app/log/test.log +32588 -33752
- data/spec/rails_app/tmp/capybara/capybara-201108261408529518409580.html +23 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261409354283519857.html +23 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261411215267908820.html +36 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261411377094743316.html +36 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261607322084409756.html +34 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261612128889477667.html +34 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261614323748273234.html +34 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261614562813014420.html +34 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261615145359399760.html +34 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261616296916249304.html +34 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261617171731033403.html +34 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261617339533158457.html +36 -0
- data/spec/rails_app/tmp/capybara/capybara-201108261620375648320872.html +41 -0
- data/spec/spec_helper.rb +7 -3
- data/spec/support/bento_spec_helper.rb +2 -2
- data/spec/support/blueprints.rb +0 -1
- metadata +97 -96
- data/spec/bento_spec.rb +0 -4
- data/spec/controllers/bento_for_routes_spec.rb +0 -55
- data/spec/rails_app/log/server.log +0 -0
data/README.rdoc
CHANGED
@@ -14,6 +14,10 @@ Replace MODEL by the class name you want to use as your account-like model, like
|
|
14
14
|
This will create a model (if one does not exist) and configure it with default Bento options.
|
15
15
|
The generator will also create a migration file (if you're running ActiveRecord) and configure your routes.
|
16
16
|
|
17
|
+
The migration files will by default set up the following database structure:
|
18
|
+
user has_many :accounts, :through => :bento_memberships
|
19
|
+
accounts has_many :users, :through => :bento_memberships
|
20
|
+
|
17
21
|
== Getting started
|
18
22
|
=== Model
|
19
23
|
This is a walkthrough with all steps you need to setup a Bento resource, including model, migration and route files.
|
@@ -28,6 +32,10 @@ Bento doesn't use attr_accessible or attr_protected inside its modules, so be su
|
|
28
32
|
Configure your routes after setting up your model. Open your config/routes.rb file and add:
|
29
33
|
bento_for :accounts
|
30
34
|
This will use your Account model to create a set of needed routes (you can see them by running `rake routes`).
|
35
|
+
You can nest other routes in bento_for just as you would with the standard resources routes method:
|
36
|
+
bento_for :accounts do
|
37
|
+
resources :projects
|
38
|
+
end
|
31
39
|
|
32
40
|
This will add bento_for :accounts to your routes file. If you want to add another model just rename or add the argument(s) to bento_for.
|
33
41
|
bento_for :accounts, :sites
|
@@ -61,8 +69,8 @@ This can be changed by overriding the after_create_url method:
|
|
61
69
|
end
|
62
70
|
|
63
71
|
== Navigating the source
|
64
|
-
|
65
|
-
|
72
|
+
The gem has a basic set of cucumber features along with a rails app.
|
73
|
+
Check them out to see some examples on how to use Bento in your application.
|
66
74
|
|
67
75
|
== Disclaimer
|
68
76
|
* The gem is still in early beta, be careful.
|
@@ -76,7 +84,32 @@ This can be changed by overriding the after_create_url method:
|
|
76
84
|
* All the gems that this gem depends on.
|
77
85
|
|
78
86
|
== TODO:
|
79
|
-
*
|
80
|
-
*
|
87
|
+
* Make it possible to create new users
|
88
|
+
* Make it possible to completely remove users
|
89
|
+
* Add inline documentation
|
81
90
|
* Make is possible to have another user model then User.
|
82
|
-
|
91
|
+
|
92
|
+
== License:
|
93
|
+
|
94
|
+
(The MIT License)
|
95
|
+
|
96
|
+
Copyright (c) 2011 Nicklas Ramhöj
|
97
|
+
|
98
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
99
|
+
a copy of this software and associated documentation files (the
|
100
|
+
'Software'), to deal in the Software without restriction, including
|
101
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
102
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
103
|
+
permit persons to whom the Software is furnished to do so, subject to
|
104
|
+
the following conditions:
|
105
|
+
|
106
|
+
The above copyright notice and this permission notice shall be
|
107
|
+
included in all copies or substantial portions of the Software.
|
108
|
+
|
109
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
110
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
111
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
112
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
113
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
114
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
115
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/bento.rb
CHANGED
@@ -1,50 +1,82 @@
|
|
1
1
|
module Bento
|
2
2
|
module Controllers
|
3
3
|
module AccountScopable
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
4
|
+
mattr_accessor :resource_names
|
5
|
+
@@resource_names = []
|
6
|
+
|
7
|
+
def self.define_methods(resource_name)
|
8
|
+
@@resource_names << resource_name.to_s.singularize
|
9
|
+
@@name = @@resource_names.first
|
10
|
+
|
11
|
+
ActiveSupport.on_load(:action_controller) do
|
12
|
+
class_eval do
|
13
|
+
def admin?
|
14
|
+
respond_to_admin? and current_user.admin?
|
15
|
+
end
|
16
|
+
|
17
|
+
def not_responding_to_admin?
|
18
|
+
(not respond_to_admin?)
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to_admin?
|
22
|
+
current_user.respond_to?(:admin?)
|
23
|
+
end
|
21
24
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
25
|
+
|
26
|
+
@@resource_names.uniq.each do |name|
|
27
|
+
(class << self; self; end).send(:define_method, "scoped_to_#{name}") do
|
28
|
+
inherit_resources
|
29
|
+
|
30
|
+
class_eval do
|
31
|
+
private
|
32
|
+
|
33
|
+
# This is where things get scoped.
|
34
|
+
# If you're using inherit_resources it will automaticly
|
35
|
+
# call your associations on this method.
|
36
|
+
# In your own code you would just use current_<my account like model>-method.
|
37
|
+
def begin_of_association_chain
|
38
|
+
begining = instance_variable_get("@#{@@name}".to_sym)
|
39
|
+
return begining if begining
|
40
|
+
|
41
|
+
begining = send("current_#{@@name}")
|
42
|
+
instance_variable_set("@#{@@name}".to_sym, begining)
|
43
|
+
begining
|
44
|
+
end
|
45
|
+
|
46
|
+
def bento_resource_by_param_or_session
|
47
|
+
if bento_resource_id
|
48
|
+
@@name.camelcase.constantize.find(bento_resource_id)
|
49
|
+
else
|
50
|
+
current_user.send(@@name)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def bento_resource_id
|
55
|
+
key, value = params.find { |key, value| key.to_s.ends_with?("#{@@name}_id") }
|
56
|
+
value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class_eval <<-RUBY, __FILE__, __LINE__+1
|
61
|
+
private
|
62
|
+
|
63
|
+
def current_#{name}
|
64
|
+
if current_user
|
65
|
+
if current_user.#{name}
|
66
|
+
current_user.#{name}
|
67
|
+
elsif not_responding_to_admin? or admin?
|
68
|
+
bento_resource_by_param_or_session
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
RUBY
|
73
|
+
end # define_method
|
74
|
+
end # @@resource_names.uniq.each
|
75
|
+
end # ActiveSupport.on_load
|
76
|
+
end # def self.define_helpers
|
77
|
+
end # module AccountScopable
|
78
|
+
end # module Controllers
|
79
|
+
end # module Bento
|
48
80
|
|
49
81
|
class ActionController::Base
|
50
82
|
extend Bento::Controllers::AccountScopable
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bento
|
2
|
+
module Models
|
3
|
+
module User
|
4
|
+
def fake_belongs_to(singular)
|
5
|
+
singular = singular.to_s
|
6
|
+
plural = singular.pluralize
|
7
|
+
|
8
|
+
define_method(singular) do
|
9
|
+
send(plural).first
|
10
|
+
end
|
11
|
+
|
12
|
+
define_method("#{singular}=") do |record|
|
13
|
+
send(plural).each(&:destroy)
|
14
|
+
self.send(plural) << record
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# TODO: only include in the user model
|
22
|
+
class ActiveRecord::Base
|
23
|
+
extend Bento::Models::User
|
24
|
+
end
|
data/lib/bento/rails/routes.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
module ActionDispatch::Routing
|
2
2
|
class Mapper
|
3
|
-
def bento_for(*resource_names)
|
3
|
+
def bento_for(*resource_names, &block)
|
4
|
+
options = resource_names.extract_options!
|
4
5
|
resource_names.map!(&:to_sym)
|
6
|
+
|
5
7
|
resource_names.each do |resource_name|
|
6
8
|
Bento::Controllers::Helpers.define_helpers(resource_name)
|
9
|
+
Bento::Controllers::AccountScopable.define_methods(resource_name)
|
10
|
+
resource_options = { :controller => account_controller(resource_name) }.merge(options)
|
7
11
|
|
8
|
-
resources(resource_name,
|
12
|
+
resources(resource_name, resource_options) do
|
9
13
|
collection { get :sign_up }
|
14
|
+
yield if block_given?
|
10
15
|
end
|
11
16
|
end
|
12
17
|
end
|
data/lib/bento/version.rb
CHANGED
@@ -11,18 +11,18 @@ module ActiveRecord
|
|
11
11
|
|
12
12
|
def generate_model
|
13
13
|
invoke "active_record:model", [name], :migration => false unless model_exists?
|
14
|
+
create_file "app/models/bento_membership.rb", bento_membership_model_content
|
14
15
|
end
|
15
16
|
|
16
17
|
def copy_bento_migration
|
17
18
|
migration_template "create_migration.rb", "db/migrate/bento_create_#{table_name}"
|
18
|
-
migration_template "
|
19
|
+
migration_template "bento_membership_migration.rb", "db/migrate/bento_create_bento_memberships"
|
19
20
|
end
|
20
21
|
|
21
22
|
def inject_bento_content
|
22
|
-
inject_into_class model_path, class_name, model_contents
|
23
|
-
|
24
|
-
|
25
|
-
CONTENT
|
23
|
+
inject_into_class model_path, class_name, model_contents
|
24
|
+
inject_into_class user_path, "User", user_model_content
|
25
|
+
inject_into_class bento_membership_path, "BentoMembership", bento_membership_model_content
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class BentoCreateBentoMemberships < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :bento_memberships do |t|
|
4
|
+
t.integer :<%= name %>_id
|
5
|
+
t.integer :user_id
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :bento_memberships, [:<%= name %>_id, :user_id], :unique => true
|
10
|
+
|
11
|
+
# If you know for sure that you don't want to be able
|
12
|
+
# to have users that belongs to several <%= name.pluralize %>
|
13
|
+
# please remove the above lines and uncomment the lines below
|
14
|
+
|
15
|
+
# add_column :users, :<%= name %>_id, :integer
|
16
|
+
# add_index :users, :<%= name %>_id
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.down
|
20
|
+
drop_table :bento_memberships
|
21
|
+
|
22
|
+
# remove_column :users, :<%= name %>_id
|
23
|
+
# remove_index :users, :<%= name %>_id
|
24
|
+
end
|
25
|
+
end
|
@@ -7,6 +7,44 @@ module Bento
|
|
7
7
|
# :all, :validations, :user_accessors, :user_association, :user_accessors, :trial
|
8
8
|
bento
|
9
9
|
|
10
|
+
# Setup accessible (or protected) attributes for your model
|
11
|
+
attr_accessible :name
|
12
|
+
CONTENT
|
13
|
+
end
|
14
|
+
|
15
|
+
def user_model_content
|
16
|
+
<<-CONTENT
|
17
|
+
has_many :bento_memberships
|
18
|
+
has_many :#{table_name}, :through => :bento_memberships
|
19
|
+
|
20
|
+
#
|
21
|
+
# Remove this method call unless you want to work with
|
22
|
+
# the has_many :through association as if it was a simple
|
23
|
+
# belongs_to :#{class_name.underscore}.
|
24
|
+
#
|
25
|
+
# If you know for sure that you don't want to be able
|
26
|
+
# to have users that belongs to several #{table_name} you
|
27
|
+
# can of course edit the generated migration files to
|
28
|
+
# not create the join model table "bento_memberships" and instead
|
29
|
+
# add a #{class_name.underscore}_id to your User model.
|
30
|
+
#
|
31
|
+
# You also need to not use the :user_association module in bento
|
32
|
+
# for example to use all in your #{class_name} model change the
|
33
|
+
# call to bento from `bento :all` to bento `:validations, :user_accessors, :user_accessors, :trial`
|
34
|
+
# then you just remove the above relations and remove the "fake_" part below.
|
35
|
+
#
|
36
|
+
fake_belongs_to :#{class_name.underscore}
|
37
|
+
CONTENT
|
38
|
+
end
|
39
|
+
|
40
|
+
def bento_membership_model_content
|
41
|
+
<<-CONTENT
|
42
|
+
class BentoMembership < ActiveRecord::Base
|
43
|
+
belongs_to :user
|
44
|
+
belongs_to :#{class_name.underscore}
|
45
|
+
|
46
|
+
attr_accessible :#{class_name.underscore}_id, :user_id
|
47
|
+
end
|
10
48
|
CONTENT
|
11
49
|
end
|
12
50
|
|
@@ -14,9 +52,21 @@ CONTENT
|
|
14
52
|
File.exists?(File.join(destination_root, model_path))
|
15
53
|
end
|
16
54
|
|
55
|
+
def bento_membership_exists?
|
56
|
+
File.exists?(File.join(destination_root, bento_membership_path))
|
57
|
+
end
|
58
|
+
|
17
59
|
def model_path
|
18
60
|
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
19
61
|
end
|
62
|
+
|
63
|
+
def bento_membership_path
|
64
|
+
@bento_membership_path ||= File.join("app", "models", "bento_membership.rb")
|
65
|
+
end
|
66
|
+
|
67
|
+
def user_path
|
68
|
+
@user_path ||= File.join("app", "models", "user.rb")
|
69
|
+
end
|
20
70
|
end
|
21
71
|
end
|
22
72
|
end
|
@@ -7,6 +7,17 @@ class UserAccessorsTestAccount < ActiveRecord::Base
|
|
7
7
|
end
|
8
8
|
|
9
9
|
describe Bento::Models::Modules::UserAccessors do
|
10
|
+
before do
|
11
|
+
# Adding alias to get the relations to work with our custom made class
|
12
|
+
|
13
|
+
BentoMembership.class_eval do
|
14
|
+
attr_accessible :user_accessors_test_account_id
|
15
|
+
def user_accessors_test_account_id=(id)
|
16
|
+
self.account_id = id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
10
21
|
let(:account_params) do
|
11
22
|
{ :name => "Hashrocket", :first_name => "Obie", :last_name => "Fernandez", :email => "obie@hashrocket.com", :password => "test1234" }
|
12
23
|
end
|
@@ -22,8 +33,7 @@ describe Bento::Models::Modules::UserAccessors do
|
|
22
33
|
context "all user attributes are blank" do
|
23
34
|
it "creates the account without the user" do
|
24
35
|
account = UserAccessorsTestAccount.new(:name => "Elabs")
|
25
|
-
account.save.should be_true
|
26
|
-
User.find_by_account_id(account.id).should be_nil
|
36
|
+
expect { account.save.should be_true }.to_not change(User, :count)
|
27
37
|
end
|
28
38
|
end
|
29
39
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Bento::Models::User do
|
4
|
+
describe ".fake_belongs_to" do
|
5
|
+
let(:user) { User.make }
|
6
|
+
let(:account) { Account.make }
|
7
|
+
before do
|
8
|
+
User.class_eval { fake_belongs_to(:account) }
|
9
|
+
user.accounts << account
|
10
|
+
end
|
11
|
+
|
12
|
+
it "defines #account" do
|
13
|
+
user.account.should == account
|
14
|
+
end
|
15
|
+
|
16
|
+
it "defines #account=" do
|
17
|
+
other_account = Account.make
|
18
|
+
user.account = other_account
|
19
|
+
|
20
|
+
user.reload.account.should == other_account
|
21
|
+
user.accounts.length.should == 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class SitesController < ActionController::Base
|
4
|
+
def show; render(:text => "s"); end
|
5
|
+
def index; render(:text => "i"); end
|
6
|
+
def new; render(:text => "n"); end
|
7
|
+
def edit; render(:text => "e"); end
|
8
|
+
def create; redirect_to sites_url; end
|
9
|
+
def update; redirect_to sites_url; end
|
10
|
+
def destroy; redirect_to sites_url; end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe SitesController do
|
14
|
+
describe "#bento_for" do
|
15
|
+
it "defines resource routes" do
|
16
|
+
with_routing do |map|
|
17
|
+
map.draw { bento_for :sites }
|
18
|
+
|
19
|
+
get(:show, :id => 1); response.should be_success
|
20
|
+
get(:index); response.should be_success
|
21
|
+
get(:new, :id => 1); response.should be_success
|
22
|
+
get(:edit, :id => 1); response.should be_success
|
23
|
+
put(:update, :id => 1); response.should be_redirect
|
24
|
+
post(:create); response.should be_redirect
|
25
|
+
put(:destroy, :id => 1); response.should be_redirect
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "allows the default options to resourcers" do
|
30
|
+
with_routing do |map|
|
31
|
+
map.draw { bento_for :sites, :only => %w[show new] }
|
32
|
+
get(:show, :id => 1); response.should be_success
|
33
|
+
get(:new); response.should be_success
|
34
|
+
expect { get(:index) }.to raise_error
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|