kitestrings 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +10 -0
- data/kitestrings.gemspec +0 -2
- data/lib/generators/kitestrings/install_generator.rb +26 -6
- data/lib/generators/kitestrings/message_templates/default.text.erb +7 -0
- data/lib/generators/kitestrings/message_templates/index.html.haml +26 -0
- data/lib/generators/kitestrings/{templates → message_templates}/message.rb.erb +19 -2
- data/lib/generators/kitestrings/message_templates/message_mailer.rb +19 -0
- data/lib/generators/kitestrings/message_templates/message_migration.rb +20 -0
- data/lib/generators/kitestrings/message_templates/message_spec.rb +73 -0
- data/lib/generators/kitestrings/message_templates/messages.rb +11 -0
- data/lib/generators/kitestrings/message_templates/messages_controller.rb +41 -0
- data/lib/generators/kitestrings/message_templates/messages_controller_spec.rb +86 -0
- data/lib/generators/kitestrings/message_templates/show.html.haml +32 -0
- data/lib/generators/kitestrings/messages_generator.rb +64 -1
- data/lib/generators/templates/{deploy.rb → config/deploy.rb} +19 -16
- data/lib/generators/templates/config/deploy/integ.rb +3 -0
- data/lib/generators/templates/config/deploy/production.rb +12 -0
- data/lib/generators/templates/config/deploy/uat.rb +3 -0
- data/lib/generators/templates/config/environments/integ.rb +21 -0
- data/lib/generators/templates/config/environments/uat.rb +21 -0
- data/lib/generators/templates/views/public/403.html +30 -0
- data/lib/kitestrings/menu.rb +10 -0
- data/lib/kitestrings/menu/admin_controller.rb +21 -0
- data/lib/kitestrings/menu/controller.rb +24 -0
- data/lib/kitestrings/menu/item.rb +94 -0
- data/lib/kitestrings/menu/item_collection.rb +29 -0
- data/lib/kitestrings/menu/model.rb +29 -0
- data/lib/kitestrings/menu/view_helper.rb +68 -0
- data/lib/kitestrings/version.rb +1 -1
- data/spec/lib/generators/kitestrings/install_generator_spec.rb +17 -13
- data/spec/lib/generators/kitestrings/messages_generator_spec.rb +31 -3
- data/spec/lib/kitestrings/menu/model_spec.rb +33 -0
- data/spec/support/active_record.rb +0 -1
- data/spec/support/generator_support.rb +15 -0
- metadata +30 -35
- data/lib/generators/templates/deploy/integ.rb +0 -21
- data/lib/generators/templates/deploy/production.rb +0 -26
- data/lib/generators/templates/deploy/uat.rb +0 -23
@@ -1,10 +1,73 @@
|
|
1
1
|
module Kitestrings
|
2
2
|
module Generators
|
3
3
|
class MessagesGenerator < Rails::Generators::Base
|
4
|
-
|
4
|
+
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
source_root File.expand_path("../message_templates", __FILE__)
|
5
8
|
|
6
9
|
def setup_messages_model
|
7
10
|
template "message.rb.erb", "app/models/message.rb"
|
11
|
+
copy_file "message_mailer.rb", "app/mailers/message_mailer.rb"
|
12
|
+
copy_file "default.text.erb", "app/views/message_mailer/default.text.erb"
|
13
|
+
copy_file "message_spec.rb", "spec/models/message_spec.rb"
|
14
|
+
copy_file "messages.rb", "spec/factories/messages.rb"
|
15
|
+
copy_file "messages_controller.rb", "app/controllers/messages_controller.rb"
|
16
|
+
copy_file "messages_controller_spec.rb", "spec/controllers/messages_controller_spec.rb"
|
17
|
+
copy_file "index.html.haml", "app/views/messages/index.html.haml"
|
18
|
+
copy_file "show.html.haml", "app/views/messages/show.html.haml"
|
19
|
+
|
20
|
+
if Dir.glob(destination_root + "/db/migrate/*create_messages.rb").count == 0
|
21
|
+
migration_template "message_migration.rb", "db/migrate/create_messages.rb"
|
22
|
+
end
|
23
|
+
|
24
|
+
routes = <<RUBY
|
25
|
+
resources :messages, only: [:index, :show]
|
26
|
+
# also nest under user, for example:
|
27
|
+
# resources :user do
|
28
|
+
# resources :messages, only: [:index, :show]
|
29
|
+
# end
|
30
|
+
RUBY
|
31
|
+
inject_into_file "config/routes.rb", routes, :before => /^end/
|
32
|
+
|
33
|
+
|
34
|
+
puts <<OUTPUT
|
35
|
+
-------------------------------------------------------------------------------
|
36
|
+
|
37
|
+
Kitestrings Message scaffold. Please complete the following manually:
|
38
|
+
|
39
|
+
1. Check config/routes.rb for nesting messages under the user model. For example:
|
40
|
+
|
41
|
+
resources :user do
|
42
|
+
resources :messages, only: [:index, :show]
|
43
|
+
end
|
44
|
+
|
45
|
+
2. Update CanCan abilities so users can read their messages, for example:
|
46
|
+
|
47
|
+
can(:read, Message) { |message| message.user == user }
|
48
|
+
can(:index_all, Message) if user.admin?
|
49
|
+
|
50
|
+
3. Add the following to your user model
|
51
|
+
|
52
|
+
has_many :messages
|
53
|
+
|
54
|
+
4. Set the default host. This is needed as the Message model needs to generate
|
55
|
+
absolute URLs to be inserted into email bodies. Example, add to routes.rb:
|
56
|
+
|
57
|
+
default_url_options :host => (ENV['DEFAULT_URL_HOST'] || 'localhost')
|
58
|
+
|
59
|
+
5. Add "message" and "message_other" to your common lets. Example:
|
60
|
+
|
61
|
+
# Messages
|
62
|
+
let(:message) { create :message, user: user }
|
63
|
+
let(:message_other) { create :message, user: user_other }
|
64
|
+
|
65
|
+
-------------------------------------------------------------------------------
|
66
|
+
OUTPUT
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.next_migration_number(dirname)
|
70
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
8
71
|
end
|
9
72
|
end
|
10
73
|
end
|
@@ -5,18 +5,20 @@ require 'airbrake/capistrano'
|
|
5
5
|
|
6
6
|
set :stages, %w(integ, uat, production)
|
7
7
|
set :default_stage, "integ"
|
8
|
-
set :application, '
|
9
|
-
set :user, '
|
8
|
+
set :application, 'APP_NAME'
|
9
|
+
set :user, 'APP_NAME'
|
10
10
|
set (:deploy_to) { "/home/#{user}/apps/#{rails_env}" }
|
11
11
|
set :deploy_via, :remote_cache
|
12
12
|
set :use_sudo, false
|
13
13
|
set :scm, 'git'
|
14
|
-
|
14
|
+
|
15
|
+
#set :repository, 'git@github.com:2rk/APP_NAME.git'
|
15
16
|
|
16
17
|
set :ssl, false
|
17
|
-
# set :ssl_certificates_path, '/home/
|
18
|
-
# set :ssl_certificates_name, '
|
18
|
+
# set :ssl_certificates_path, '/home/APP_NAME/ssl'
|
19
|
+
# set :ssl_certificates_name, 'APP_NAME'
|
19
20
|
|
21
|
+
set :rvm_ruby_string, File.read(".ruby-version").chomp
|
20
22
|
set :mysql_password, YAML::load_file("config/database.yml.server")["production"]["password"]
|
21
23
|
set :bundle_flags, "--deployment"
|
22
24
|
|
@@ -68,9 +70,11 @@ conf
|
|
68
70
|
|
69
71
|
|
70
72
|
task :github_ssh_key do
|
71
|
-
run "ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '';
|
73
|
+
run "if [ ! -f ~/.ssh/id_rsa ]; then ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ''; fi"
|
74
|
+
# This will return an error back but it is not an issue
|
75
|
+
run "ssh -T -oStrictHostKeyChecking=no git@github.com; true"
|
76
|
+
run "cat .ssh/id_rsa.pub"
|
72
77
|
end
|
73
|
-
|
74
78
|
task :symlink_config do
|
75
79
|
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
|
76
80
|
end
|
@@ -102,7 +106,7 @@ namespace :ruby_make do
|
|
102
106
|
desc "Run a task on a remote server."
|
103
107
|
# run like: cap staging rake:invoke task=a_certain_task
|
104
108
|
task :invoke do
|
105
|
-
run("cd #{deploy_to}/current;
|
109
|
+
run("cd #{deploy_to}/current; bin/rake #{ENV['task']} RAILS_ENV=#{rails_env}")
|
106
110
|
end
|
107
111
|
end
|
108
112
|
|
@@ -121,16 +125,15 @@ namespace :deploy do
|
|
121
125
|
end
|
122
126
|
desc "reload the database with seed data"
|
123
127
|
task :seed do
|
124
|
-
run "cd #{current_path};
|
128
|
+
run "cd #{current_path}; bin/rake db:seed RAILS_ENV=#{rails_env}"
|
125
129
|
end
|
126
130
|
end
|
127
131
|
|
128
|
-
namespace :rvm do
|
129
|
-
task :trust_rvmrc do
|
130
|
-
run "rvm rvmrc trust #{release_path}"
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
after "deploy", "rvm:trust_rvmrc"
|
135
132
|
after 'deploy:setup', 'deploy:create_database', 'deploy:github_ssh_key', 'deploy:nginx_conf', 'deploy:create_shared_database_config'
|
136
133
|
after 'deploy:cold', 'deploy:airbrake_test'
|
134
|
+
|
135
|
+
before 'deploy:setup', 'rvm:install_rvm' # update RVM
|
136
|
+
before 'deploy:setup', 'rvm:install_ruby'
|
137
|
+
|
138
|
+
# load additional deploy steps and configuration from lib/capistrano/*.cap files:
|
139
|
+
Dir["lib/capistrano/*.cap"].each { |file| load file }
|
@@ -0,0 +1,12 @@
|
|
1
|
+
set :rails_env, 'production'
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
|
4
|
+
|
5
|
+
set :rvm_install_ruby_params, '--verify-downloads 1'
|
6
|
+
set :rvm_type, :user
|
7
|
+
set :branch, 'master'
|
8
|
+
|
9
|
+
#default_run_option[:pty] = true
|
10
|
+
ssh_options[:forward_agent] = true
|
11
|
+
|
12
|
+
#server 'APP_NAME.production.tworedkites.com', :web, :app, :db, primary: true
|
@@ -0,0 +1,21 @@
|
|
1
|
+
load File.expand_path("../production.rb", __FILE__)
|
2
|
+
|
3
|
+
Rails.application.configure do
|
4
|
+
|
5
|
+
config.loglevel = :debug
|
6
|
+
|
7
|
+
# config.airbrake_api_key = 'AIRBRAKE_KEY'
|
8
|
+
|
9
|
+
# used by message model to create links (outside of a controller / mailer)
|
10
|
+
Rails.application.routes.default_url_options[:host] = 'APP_NAME.integ.tworedkites.com'
|
11
|
+
|
12
|
+
# config.action_mailer.delivery_method = :mail_gate
|
13
|
+
# config.action_mailer.mail_gate_settings = {
|
14
|
+
# :whitelist => /VALIDATE_EMAIL_REGEX/,
|
15
|
+
# :subject_prefix => '[INTEG] ',
|
16
|
+
# :delivery_method => :smtp,
|
17
|
+
# :smtp_settings => {
|
18
|
+
# :address => 'smtp.example.com'
|
19
|
+
# }
|
20
|
+
# }
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
load File.expand_path("../production.rb", __FILE__)
|
2
|
+
|
3
|
+
Rails.application.configure do
|
4
|
+
|
5
|
+
config.log_level = :info
|
6
|
+
|
7
|
+
# config.airbrake_api_key = 'AIRBRAKE_KEY'
|
8
|
+
|
9
|
+
# used by message model to create links (outside of a controller / mailer)
|
10
|
+
Rails.application.routes.default_url_options[:host] = 'APP_NAME.uat.tworedkites.com'
|
11
|
+
|
12
|
+
# config.action_mailer.delivery_method = :mail_gate
|
13
|
+
# config.action_mailer.mail_gate_settings = {
|
14
|
+
# :whitelist => /VALIDATE_EMAIL_REGEX/,
|
15
|
+
# :subject_prefix => '[UAT] ',
|
16
|
+
# :delivery_method => :smtp,
|
17
|
+
# :smtp_settings => {
|
18
|
+
# :address => 'smtp.example.com'
|
19
|
+
# }
|
20
|
+
# }
|
21
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Access Denied (403)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/500.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>Access Denied.</h1>
|
23
|
+
<p>
|
24
|
+
You do not have permissions to view the current page.
|
25
|
+
</p>
|
26
|
+
<p> </p>
|
27
|
+
<p>Click <a href="/">here</a> to return to the home page.</p>
|
28
|
+
</div>
|
29
|
+
</body>
|
30
|
+
</html>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kitestrings
|
2
|
+
module Menu::AdminController
|
3
|
+
def menu_context
|
4
|
+
Admin.new
|
5
|
+
end
|
6
|
+
|
7
|
+
# this class acts like a Menu::Item
|
8
|
+
class Admin
|
9
|
+
|
10
|
+
# pretend to be a persisted resource (new pages don't show context menu)
|
11
|
+
def persisted?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
# use 'admin' as the menu partial name
|
16
|
+
def partial_name
|
17
|
+
"admin"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Kitestrings
|
2
|
+
module Menu::Controller
|
3
|
+
# return an array of the menu items constructed as polymorphic paths. For example, if loaded_resources was:
|
4
|
+
# [Company:1, Project:2, Audit:3] then this would return an array of Menu::Item objects for the following paths:
|
5
|
+
# - /companies/1
|
6
|
+
# - /companies/1/projects/2
|
7
|
+
# - /companies/1/projects/2/audits/3
|
8
|
+
#
|
9
|
+
# Each item is constructed with polymorphic path
|
10
|
+
def loaded_menu_items
|
11
|
+
@loaded_menu_items ||= Menu::ItemCollection.new(loaded_resources)
|
12
|
+
end
|
13
|
+
|
14
|
+
# get the menu item for the contextual menu (second row). On an index page, this is the item the index is nested
|
15
|
+
# under, if present. For normal pages it is the last item in the array.
|
16
|
+
def current_menu_item
|
17
|
+
if action_name == "index"
|
18
|
+
loaded_menu_items[-2]
|
19
|
+
else
|
20
|
+
loaded_menu_items[-1]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Kitestrings::Menu
|
2
|
+
# A class to represent an item in the menu. It is capable of looking up menu item paths and names and a link id,
|
3
|
+
# all the required data to construct links, include links to subpaths
|
4
|
+
class Item
|
5
|
+
include Rails.application.routes.url_helpers
|
6
|
+
|
7
|
+
attr :resources
|
8
|
+
attr_accessor :active
|
9
|
+
|
10
|
+
def initialize(resources)
|
11
|
+
@resources = resources
|
12
|
+
end
|
13
|
+
|
14
|
+
# the path of the item. eg: /companies/1/projects/2/audits/3
|
15
|
+
def path
|
16
|
+
@path ||= polymorphic_path @resources
|
17
|
+
end
|
18
|
+
|
19
|
+
# return a new item with the given extra resources added to the resource list.
|
20
|
+
def sub_item(*extras)
|
21
|
+
Item.new([*@resources, *extras].compact)
|
22
|
+
end
|
23
|
+
|
24
|
+
def parent_item
|
25
|
+
Item.new(resources[0..-2])
|
26
|
+
end
|
27
|
+
|
28
|
+
# return the menu display name for the object. This defaults to the .name method of an instance, and the
|
29
|
+
# localised human name for classes.
|
30
|
+
def name
|
31
|
+
object.try(:menu_display_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
# return the name of a menu partial to use for contextual menus relating to this item.
|
35
|
+
def partial_name
|
36
|
+
last = @resources.last
|
37
|
+
klass = last.is_a?(Class) ? last : last.class
|
38
|
+
klass.model_name.underscore
|
39
|
+
end
|
40
|
+
|
41
|
+
# fetch the last object in the chain. This is the resource that is actually being rendered. If this is an
|
42
|
+
# index action, this will be the class representing the type to be shown in the list.
|
43
|
+
def object
|
44
|
+
@resources.last
|
45
|
+
end
|
46
|
+
|
47
|
+
# a string to use as a link id in the menu link. Eg: for the path /companies/1/projects/2, the link would be
|
48
|
+
# menu_companies_projects_link
|
49
|
+
def link_id
|
50
|
+
names = @resources.map do |resource|
|
51
|
+
case resource
|
52
|
+
when Class
|
53
|
+
resource.name.pluralize.downcase
|
54
|
+
else
|
55
|
+
resource.class.name.downcase
|
56
|
+
end
|
57
|
+
end
|
58
|
+
"menu_#{names.join('_')}_link"
|
59
|
+
end
|
60
|
+
|
61
|
+
# Active is set on the last item in the Menu::ItemCollection based on the assumption that this is the active item
|
62
|
+
# in the collection.
|
63
|
+
def active?
|
64
|
+
@active
|
65
|
+
end
|
66
|
+
|
67
|
+
# Should the item be hidden in the menus? If so, menu_link_to will not generate any output. Implement a menu_hidden
|
68
|
+
# instance or class method to hide that instance or class from the menu.
|
69
|
+
def hidden?
|
70
|
+
if object.respond_to? :menu_hidden
|
71
|
+
object.menu_hidden
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def collection?
|
76
|
+
object.is_a?(Class)
|
77
|
+
end
|
78
|
+
|
79
|
+
# if this item is for a resource instance (eg: companies/1 => <# Company id:1 #>, then make a new item representing
|
80
|
+
# the collection of that class, eg: companies/ => <# Company class #>
|
81
|
+
def index_item
|
82
|
+
if @resources.last && @resources.last.is_a?(ActiveRecord::Base)
|
83
|
+
index_resources = @resources.dup
|
84
|
+
index_resources << index_resources.pop.class
|
85
|
+
Item.new index_resources
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# true if the object is persisted. Classes are not persisted.
|
90
|
+
def persisted?
|
91
|
+
object.respond_to?(:persisted?) && object.persisted?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Kitestrings
|
4
|
+
class Menu::ItemCollection < ::SimpleDelegator
|
5
|
+
attr :items
|
6
|
+
|
7
|
+
def initialize(loaded_resources)
|
8
|
+
length = loaded_resources.length
|
9
|
+
@items = (0...length).map do |count|
|
10
|
+
Menu::Item.new loaded_resources[0..count]
|
11
|
+
end
|
12
|
+
|
13
|
+
# if the last item in the resources is a new_record? object, then substitute it for the class. This will
|
14
|
+
# cause polymorphic path to show the #index action in the breadcrumb instead of the new action, or a route
|
15
|
+
# error looking for an object that has no id.
|
16
|
+
last = @items.last
|
17
|
+
if last && last.object.respond_to?(:new_record?) && last.object.new_record?
|
18
|
+
@items.pop
|
19
|
+
@items << Menu::Item.new(last.resources[0..-2] + [last.object.class])
|
20
|
+
end
|
21
|
+
|
22
|
+
# the last item in the array is assumed to be active.
|
23
|
+
@items.last.active = true unless items.empty?
|
24
|
+
|
25
|
+
# delegate all methods to this array object
|
26
|
+
super(@items)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Kitestrings::Menu::Model
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
class_attribute :menu_name_method
|
6
|
+
|
7
|
+
# default to :name
|
8
|
+
self.menu_name_method = :name
|
9
|
+
end
|
10
|
+
|
11
|
+
# get the display name for this item in the menu structure. Defaults to the :name method, can be specified by setting
|
12
|
+
# the menu_name_method class attribute on the class.
|
13
|
+
def menu_display_name
|
14
|
+
case
|
15
|
+
when respond_to?(menu_name_method)
|
16
|
+
self.send(menu_name_method)
|
17
|
+
else
|
18
|
+
"##{to_key}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
# Get the display name of the collection for this class (index action). This uses ActiveModel::Naming to fetch
|
24
|
+
# the plural name of the resource class.
|
25
|
+
def menu_display_name
|
26
|
+
self.model_name.human.pluralize.titlecase
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|