dry_crud 1.6.0 → 1.7.0
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 +25 -10
- data/Rakefile +30 -8
- data/VERSION +1 -1
- data/lib/generators/dry_crud/dry_crud_generator.rb +15 -2
- data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +18 -10
- data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +14 -11
- data/lib/generators/dry_crud/templates/app/helpers/crud_helper.rb +71 -29
- data/lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb +40 -3
- data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +8 -27
- data/lib/generators/dry_crud/templates/app/helpers/standard_table_builder.rb +13 -6
- data/lib/generators/dry_crud/templates/app/views/crud/_form.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/_form.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +4 -4
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.haml +5 -5
- data/lib/generators/dry_crud/templates/spec/controllers/crud_test_models_controller_spec.rb +433 -0
- data/lib/generators/dry_crud/templates/spec/helpers/crud_helper_spec.rb +146 -0
- data/lib/generators/dry_crud/templates/spec/helpers/list_helper_spec.rb +154 -0
- data/lib/generators/dry_crud/templates/spec/helpers/standard_form_builder_spec.rb +215 -0
- data/lib/generators/dry_crud/templates/spec/helpers/standard_helper_spec.rb +387 -0
- data/lib/generators/dry_crud/templates/spec/helpers/standard_table_builder_spec.rb +120 -0
- data/lib/generators/dry_crud/templates/spec/support/crud_controller_examples.rb +244 -0
- data/lib/generators/dry_crud/templates/spec/support/crud_controller_test_helper.rb +160 -0
- data/lib/generators/dry_crud/templates/test/crud_test_model.rb +45 -18
- data/lib/generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb +19 -9
- data/lib/generators/dry_crud/templates/test/functional/crud_test_models_controller_test.rb +11 -14
- data/lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb +26 -13
- data/lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb +0 -4
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_form_builder_test.rb +6 -0
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb +9 -35
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_table_builder_test.rb +5 -4
- data/test/templates/Gemfile +3 -1
- data/test/templates/app/controllers/people_controller.rb +1 -1
- data/test/templates/app/controllers/vips_controller.rb +1 -1
- data/test/templates/app/models/city.rb +1 -1
- data/test/templates/app/views/admin/cities/_form.html.erb +1 -1
- data/test/templates/app/views/admin/cities/_form.html.haml +1 -1
- data/test/templates/app/views/admin/countries/_list.html.erb +3 -4
- data/test/templates/app/views/admin/countries/_list.html.haml +3 -4
- data/test/templates/app/views/ajax/_form.html.erb +1 -1
- data/test/templates/app/views/ajax/_form.html.haml +1 -1
- data/test/templates/spec/controllers/admin/cities_controller_spec.rb +74 -0
- data/test/templates/spec/controllers/admin/countries_controller_spec.rb +56 -0
- data/test/templates/spec/controllers/people_controller_spec.rb +80 -0
- data/test/templates/spec/routing/cities_routing_spec.rb +11 -0
- data/test/templates/spec/routing/countries_routing_spec.rb +11 -0
- data/test/templates/test/functional/admin/cities_controller_test.rb +1 -1
- data/test/templates/test/functional/admin/countries_controller_test.rb +1 -1
- data/test/templates/test/functional/people_controller_test.rb +3 -3
- metadata +18 -7
data/README.rdoc
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
= DRY CRUD
|
2
2
|
|
3
|
+
{<img src="https://secure.travis-ci.org/codez/dry_crud.png" />}[http://travis-ci.org/codez/dry_crud]
|
4
|
+
|
3
5
|
DRY CRUD generates simple and extendable controller, views and helpers that support you to DRY up the CRUD code in your Rails project. Start with these elements and build a clean base to efficiently develop your application upon.
|
4
6
|
|
5
7
|
Create your Rails application directly with the DRY CRUD application template:
|
6
8
|
|
7
|
-
rails new
|
9
|
+
rails new APP_NAME -m https://raw.github.com/codez/dry_crud/master/template.rb
|
8
10
|
|
9
11
|
If your application already exists or you prefer the DIY way, then install the Gem (<tt>gem install dry_crud</tt>), add it to your Gemfile and run the generator. You may remove the Gemfile entry again afterwards, it is not required anymore.
|
10
12
|
|
11
|
-
rails generate dry_crud
|
13
|
+
rails generate dry_crud [--templates haml] [--tests rspec]
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
rails generate dry_crud -t haml
|
15
|
+
By default, DRY CRUD generates ERB templates and Test::Unit tests. Pass the options above to generate HAML templates and/or RSpec examples instead.
|
16
16
|
|
17
17
|
To integrate DRY CRUD into your code, only a few additions are required:
|
18
18
|
|
@@ -162,10 +162,10 @@ To render custom columns, use the :col method:
|
|
162
162
|
|
163
163
|
Forms work very similar. In the most simple case, you just have to specify which attributes of a model to create input fields for, and you get a complete form with error messages, labeled input fields according the column types and a save button:
|
164
164
|
|
165
|
-
<%=
|
165
|
+
<%= crud_form(@person, :firstname, :lastname, :age, :city) -%>
|
166
166
|
|
167
167
|
Of course, custom input fields may be defined as well:
|
168
|
-
<%=
|
168
|
+
<%= crud_form(@person, :url => custom_update_person_path(@person.id)) do |f| %>
|
169
169
|
<%= f.labeled_input_fields :firstname, :lastname %>
|
170
170
|
<%= f.labeled(:sex) do %>
|
171
171
|
<%= f.radio_button :sex, true %> female
|
@@ -286,7 +286,9 @@ views/shared/_error_messages.html.erb:: Partial to display the validation errors
|
|
286
286
|
|
287
287
|
views/layouts/crud.html.erb:: An example layout showing how to use the <tt>@title</tt> and +flash+. Most probably you want to merge this with your <tt>application.html.erb</tt> or adapt the main CRUD templates, so you wont need this file.
|
288
288
|
|
289
|
-
views/layouts/
|
289
|
+
views/layouts/_flash.html.erb:: An simple partial to display the various flash messages. Included from <tt>crud.html.erb</tt>.
|
290
|
+
|
291
|
+
views/layouts/_nav.html.erb:: An empty file to put your navigation into. Included from <tt>crud.html.erb</tt>.
|
290
292
|
|
291
293
|
app/assets/stylesheets/crud.scss:: A simple SCSS with all the classes and ids used in the CRUD code.
|
292
294
|
|
@@ -299,9 +301,22 @@ app/assets/images/action/*.png:: Some sample action icons from the {Open Icon Li
|
|
299
301
|
|
300
302
|
{test/custom_assertions.rb}[http://codez.ch/dry_crud/CustomAssertions.html]:: A handful of convenient assertions. Include this module into your <tt>test_helper.rb</tt> file.
|
301
303
|
|
302
|
-
{test/
|
304
|
+
{test/functional/crud_controller_test_helper.rb}[http://codez.ch/dry_crud/CrudControllerTestHelper.html]:: A module to include into the functional tests for your +CrudController+ subclasses. Contains a handful of CRUD functionality tests for the provided implementation. So for each new CRUD controller, you get 20 tests for free.
|
305
|
+
|
306
|
+
test/functional/crud_test_models_controller_test.rb:: Functional tests for the basic +CrudController+ functionality.
|
303
307
|
|
304
308
|
test/several other tests:: Testing the provided implementation and a great base to test your adaptions of the CRUD code.
|
305
309
|
|
306
310
|
|
307
|
-
|
311
|
+
=== Specs:
|
312
|
+
|
313
|
+
spec/support/crud_controller_examples.rb:: A whole set of shared exampled to include into your controller specs. See <tt>spec/controllers/crud_test_models_controller_spec.rb</tt> for usage. So for each new CRUD controller, you get all the basic specs for free.
|
314
|
+
|
315
|
+
spec/support/crud_controller_test_helper.rb:: Convenience methods used by the crud controller examples.
|
316
|
+
|
317
|
+
{spec/support/crud_test_model.rb}[http://codez.ch/dry_crud/CrudTestHelper.html]:: A dummy model to run CRUD tests against.
|
318
|
+
|
319
|
+
spec/controllers/crud_test_models_controller_spec.rb:: Controller specs to test the basic +CrudController+ functionality.
|
320
|
+
|
321
|
+
spec/helpers/*_spec.rb:: The specs for all the helpers included in DRY CRUD.
|
322
|
+
|
data/Rakefile
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake/testtask'
|
3
|
+
require 'rspec/core/rake_task'
|
3
4
|
require 'rubygems/package_task'
|
4
5
|
require 'rdoc/task'
|
5
6
|
|
@@ -11,15 +12,25 @@ GENERATOR_ROOT = File.join(File.dirname(__FILE__), 'lib', 'generators', 'dry_cru
|
|
11
12
|
task :default => :test
|
12
13
|
|
13
14
|
desc "Run all tests"
|
14
|
-
task :test => ['test:
|
15
|
-
|
15
|
+
task :test => ['test:unit', 'test:spec']
|
16
|
+
|
17
|
+
|
18
|
+
namespace :test do
|
19
|
+
|
20
|
+
desc "Run Test::Unit tests"
|
21
|
+
Rake::TestTask.new(:unit => 'test:app:init') do |test|
|
16
22
|
test.libs << "test/test_app/test"
|
17
23
|
test.test_files = Dir[ "test/test_app/test/**/*_test.rb" ]
|
18
24
|
test.verbose = true
|
19
25
|
end
|
20
|
-
|
26
|
+
|
27
|
+
desc "Run RSpec tests"
|
28
|
+
RSpec::Core::RakeTask.new(:spec => 'test:app:init') do |t|
|
29
|
+
t.ruby_opts = "-I test/test_app/spec"
|
30
|
+
t.pattern = "test/test_app/spec/**/*_spec.rb"
|
31
|
+
end
|
32
|
+
|
21
33
|
|
22
|
-
namespace :test do
|
23
34
|
namespace :app do
|
24
35
|
task :environment do
|
25
36
|
ENV['RAILS_ROOT'] = TEST_APP_ROOT
|
@@ -33,7 +44,8 @@ namespace :test do
|
|
33
44
|
unless File.exist?(TEST_APP_ROOT)
|
34
45
|
sh "rails new #{TEST_APP_ROOT} --skip-bundle"
|
35
46
|
FileUtils.cp(File.join(File.dirname(__FILE__), 'test', 'templates', 'Gemfile'), TEST_APP_ROOT)
|
36
|
-
sh "cd #{TEST_APP_ROOT}; bundle install" # update Gemfile.lock
|
47
|
+
sh "cd #{TEST_APP_ROOT}; bundle install --local" # update Gemfile.lock
|
48
|
+
sh "cd #{TEST_APP_ROOT}; rails g rspec:install"
|
37
49
|
FileUtils.rm_f(File.join(TEST_APP_ROOT, 'test', 'performance', 'browsing_test.rb'))
|
38
50
|
end
|
39
51
|
end
|
@@ -42,7 +54,10 @@ namespace :test do
|
|
42
54
|
task :generate_crud => [:create, :environment] do
|
43
55
|
require File.join(GENERATOR_ROOT, 'dry_crud_generator')
|
44
56
|
|
45
|
-
DryCrudGenerator.new(
|
57
|
+
DryCrudGenerator.new([], {:force => true,
|
58
|
+
:templates => ENV['HAML'] ? 'haml' : 'erb',
|
59
|
+
:tests => 'all'},
|
60
|
+
:destination_root => TEST_APP_ROOT).invoke_all
|
46
61
|
end
|
47
62
|
|
48
63
|
desc "Populates the test application with some models and controllers"
|
@@ -50,6 +65,10 @@ namespace :test do
|
|
50
65
|
# copy test app templates
|
51
66
|
FileUtils.cp_r(File.join(File.dirname(__FILE__), 'test', 'templates', '.'), TEST_APP_ROOT)
|
52
67
|
|
68
|
+
# copy shared fixtures
|
69
|
+
FileUtils.cp_r(File.join(File.dirname(__FILE__), 'test', 'templates', 'test', 'fixtures'),
|
70
|
+
File.join(TEST_APP_ROOT, 'spec'))
|
71
|
+
|
53
72
|
# replace some unused files
|
54
73
|
FileUtils.rm_f(File.join(TEST_APP_ROOT, 'public', 'index.html'))
|
55
74
|
layouts = File.join(TEST_APP_ROOT, 'app', 'views', 'layouts')
|
@@ -65,7 +84,10 @@ namespace :test do
|
|
65
84
|
Dir.glob(File.join(TEST_APP_ROOT, 'app', 'views', '**', "*.#{exclude}")).each do |f|
|
66
85
|
FileUtils.rm(f)
|
67
86
|
end
|
68
|
-
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "Insert seed data into the test database"
|
90
|
+
task :seed => :populate do
|
69
91
|
# migrate the database
|
70
92
|
FileUtils.cd(TEST_APP_ROOT) do
|
71
93
|
sh "rake db:migrate db:seed RAILS_ENV=development --trace"
|
@@ -74,7 +96,7 @@ namespace :test do
|
|
74
96
|
end
|
75
97
|
|
76
98
|
desc "Initializes the test application with a couple of classes"
|
77
|
-
task :init => [:
|
99
|
+
task :init => [:seed,
|
78
100
|
:customize]
|
79
101
|
|
80
102
|
desc "Customize some of the functionality provided by dry_crud"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.7.0
|
@@ -3,6 +3,7 @@ require 'rails/generators'
|
|
3
3
|
class DryCrudGenerator < Rails::Generators::Base
|
4
4
|
|
5
5
|
class_options %w(templates -t) => 'erb'
|
6
|
+
class_options %w(tests) => 'testunit'
|
6
7
|
|
7
8
|
|
8
9
|
def self.source_root
|
@@ -11,16 +12,28 @@ class DryCrudGenerator < Rails::Generators::Base
|
|
11
12
|
|
12
13
|
def install_dry_crud
|
13
14
|
# copy everything in template subfolders
|
14
|
-
|
15
|
+
exclude_template = options[:templates].downcase == 'haml' ? '.erb' : '.haml'
|
16
|
+
|
17
|
+
exclude_test_dir = case options[:tests].downcase
|
18
|
+
when 'rspec' then 'test'
|
19
|
+
when 'all' then 'exclude_nothing'
|
20
|
+
else 'spec'
|
21
|
+
end
|
15
22
|
|
16
23
|
Dir.chdir(self.class.source_root) do
|
17
24
|
Dir.glob(File.join('**', '**')).sort.each do |file_source|
|
18
25
|
if !File.directory?(file_source) &&
|
19
|
-
!file_source.end_with?(
|
26
|
+
!file_source.end_with?(exclude_template) &&
|
27
|
+
!file_source.start_with?(exclude_test_dir) &&
|
20
28
|
file_source != 'INSTALL'
|
21
29
|
copy_file(file_source)
|
22
30
|
end
|
23
31
|
end
|
32
|
+
|
33
|
+
unless exclude_test_dir == 'spec'
|
34
|
+
copy_file(File.join('test', 'crud_test_model.rb'),
|
35
|
+
File.join('spec', 'support', 'crud_test_model.rb'))
|
36
|
+
end
|
24
37
|
end
|
25
38
|
|
26
39
|
readme "INSTALL"
|
@@ -48,12 +48,13 @@ class CrudController < ListController
|
|
48
48
|
# There are before and after create callbacks to hook into the action.
|
49
49
|
# To customize the response, you may overwrite this action and call
|
50
50
|
# super with a block that gets the format parameter.
|
51
|
+
# Specify a :location option if you wish to do a custom redirect.
|
51
52
|
# POST /entries
|
52
53
|
# POST /entries.json
|
53
|
-
def create(&block)
|
54
|
+
def create(options = {}, &block)
|
54
55
|
assign_attributes
|
55
56
|
created = with_callbacks(:create, :save) { entry.save }
|
56
|
-
respond_with(entry, :success => created, &block)
|
57
|
+
respond_with(entry, options.reverse_merge(:success => created), &block)
|
57
58
|
end
|
58
59
|
|
59
60
|
# Display a form to edit an exisiting entry of this model.
|
@@ -66,28 +67,30 @@ class CrudController < ListController
|
|
66
67
|
# There are before and after update callbacks to hook into the action.
|
67
68
|
# To customize the response, you may overwrite this action and call
|
68
69
|
# super with a block that gets the format parameter.
|
70
|
+
# Specify a :location option if you wish to do a custom redirect.
|
69
71
|
# PUT /entries/1
|
70
72
|
# PUT /entries/1.json
|
71
|
-
def update(&block)
|
73
|
+
def update(options = {}, &block)
|
72
74
|
assign_attributes
|
73
75
|
updated = with_callbacks(:update, :save) { entry.save }
|
74
|
-
respond_with(entry, :success => updated, &block)
|
76
|
+
respond_with(entry, options.reverse_merge(:success => updated), &block)
|
75
77
|
end
|
76
78
|
|
77
79
|
# Destroy an existing entry of this model.
|
78
80
|
# There are before and after destroy callbacks to hook into the action.
|
79
81
|
# To customize the response, you may overwrite this action and call
|
80
82
|
# super with a block that gets success and format parameters.
|
83
|
+
# Specify a :location option if you wish to do a custom redirect.
|
81
84
|
# DELETE /entries/1
|
82
85
|
# DELETE /entries/1.json
|
83
|
-
def destroy(&block)
|
86
|
+
def destroy(options = {}, &block)
|
84
87
|
destroyed = run_callbacks(:destroy) { entry.destroy }
|
85
88
|
flash[:alert] ||= error_messages.presence || flash_message(:failure) if !destroyed && request.format == :html
|
86
89
|
location = !destroyed && request.env["HTTP_REFERER"].presence || index_url
|
87
|
-
respond_with(entry, :success => destroyed, :location => location, &block)
|
90
|
+
respond_with(entry, options.reverse_merge(:success => destroyed, :location => location), &block)
|
88
91
|
end
|
89
92
|
|
90
|
-
|
93
|
+
private
|
91
94
|
|
92
95
|
############# CUSTOMIZABLE HELPER METHODS ##############################
|
93
96
|
|
@@ -108,7 +111,7 @@ class CrudController < ListController
|
|
108
111
|
|
109
112
|
# Assigns the attributes from the params to the model entry.
|
110
113
|
def assign_attributes
|
111
|
-
entry.attributes =
|
114
|
+
entry.attributes = model_params
|
112
115
|
end
|
113
116
|
|
114
117
|
# A label for the current entry, including the model name.
|
@@ -144,13 +147,18 @@ class CrudController < ListController
|
|
144
147
|
def error_messages
|
145
148
|
@@helper.safe_join(entry.errors.full_messages, '<br/>'.html_safe)
|
146
149
|
end
|
150
|
+
|
151
|
+
# The form params for this model.
|
152
|
+
def model_params
|
153
|
+
params[model_identifier]
|
154
|
+
end
|
147
155
|
|
148
156
|
|
149
157
|
class << self
|
150
158
|
# The identifier of the model used for form parameters.
|
151
159
|
# I.e., the symbol of the underscored model name.
|
152
160
|
def model_identifier
|
153
|
-
@model_identifier ||= model_class.
|
161
|
+
@model_identifier ||= model_class.model_name.param_key
|
154
162
|
end
|
155
163
|
|
156
164
|
# Convenience callback to apply a callback on both form actions (new and edit).
|
@@ -168,7 +176,7 @@ class CrudController < ListController
|
|
168
176
|
super(controller, with_path_args(resources, controller), options)
|
169
177
|
end
|
170
178
|
|
171
|
-
|
179
|
+
private
|
172
180
|
|
173
181
|
# Check whether the resource has errors. Additionally checks the :success option.
|
174
182
|
def has_errors?
|
@@ -23,7 +23,7 @@ class ListController < ApplicationController
|
|
23
23
|
respond_with(entries, &block)
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
private
|
27
27
|
|
28
28
|
# Helper method to access the entries to be displayed in the current index page in an uniform way.
|
29
29
|
def entries
|
@@ -52,7 +52,7 @@ class ListController < ApplicationController
|
|
52
52
|
# Get the instance variable named after the model_class.
|
53
53
|
# If the collection variable is required, pass true as the second argument.
|
54
54
|
def get_model_ivar(plural = false)
|
55
|
-
name = model_class
|
55
|
+
name = ivar_name(model_class)
|
56
56
|
name = name.pluralize if plural
|
57
57
|
instance_variable_get(:"@#{name}")
|
58
58
|
end
|
@@ -61,13 +61,17 @@ class ListController < ApplicationController
|
|
61
61
|
# If the value is a collection, sets the plural name.
|
62
62
|
def set_model_ivar(value)
|
63
63
|
name = if value.respond_to?(:klass) # ActiveRecord::Relation
|
64
|
-
value.klass.
|
64
|
+
ivar_name(value.klass).pluralize
|
65
65
|
elsif value.respond_to?(:each) # Array
|
66
|
-
value.first.klass.
|
66
|
+
ivar_name(value.first.klass).pluralize
|
67
67
|
else
|
68
|
-
value.class
|
68
|
+
ivar_name(value.class)
|
69
69
|
end
|
70
|
-
instance_variable_set(:"@#{name
|
70
|
+
instance_variable_set(:"@#{name}", value)
|
71
|
+
end
|
72
|
+
|
73
|
+
def ivar_name(klass)
|
74
|
+
klass.model_name.param_key
|
71
75
|
end
|
72
76
|
|
73
77
|
class << self
|
@@ -102,14 +106,13 @@ class ListController < ApplicationController
|
|
102
106
|
# If a callback renders or redirects, the action is not rendered.
|
103
107
|
def render_with_callbacks(*args, &block)
|
104
108
|
options = _normalize_render(*args, &block)
|
105
|
-
p options if options[:location] == :back
|
106
109
|
callback = "render_#{options[:template]}"
|
107
110
|
run_callbacks(callback) if respond_to?(:"_run_#{callback}_callbacks", true)
|
108
111
|
|
109
112
|
render_without_callbacks(*args, &block) unless performed?
|
110
113
|
end
|
111
114
|
|
112
|
-
|
115
|
+
private
|
113
116
|
|
114
117
|
# Helper method the run the given block in between the before and after
|
115
118
|
# callbacks of the given kinds.
|
@@ -145,7 +148,7 @@ class ListController < ApplicationController
|
|
145
148
|
controller.alias_method_chain :list_entries, :search
|
146
149
|
end
|
147
150
|
|
148
|
-
|
151
|
+
private
|
149
152
|
|
150
153
|
# Enhance the list entries with an optional search criteria
|
151
154
|
def list_entries_with_search
|
@@ -192,7 +195,7 @@ class ListController < ApplicationController
|
|
192
195
|
controller.alias_method_chain :list_entries, :sort
|
193
196
|
end
|
194
197
|
|
195
|
-
|
198
|
+
private
|
196
199
|
|
197
200
|
# Enhance the list entries with an optional sort order.
|
198
201
|
def list_entries_with_sort
|
@@ -302,7 +305,7 @@ class ListController < ApplicationController
|
|
302
305
|
controller.alias_method_chain :path_args, :nesting
|
303
306
|
end
|
304
307
|
|
305
|
-
|
308
|
+
private
|
306
309
|
|
307
310
|
# Returns the direct parent ActiveRecord of the current request, if any.
|
308
311
|
def parent
|
@@ -3,40 +3,76 @@
|
|
3
3
|
# is included in CrudController.
|
4
4
|
module CrudHelper
|
5
5
|
|
6
|
-
# Renders a
|
7
|
-
# given attribute array
|
8
|
-
# may be given as the last argument.
|
6
|
+
# Renders a crud form for the current entry with default_attrs or the
|
7
|
+
# given attribute array. An options hash may be given as the last argument.
|
9
8
|
# If a block is given, a custom form may be rendered and attrs is ignored.
|
10
|
-
def
|
11
|
-
|
12
|
-
|
9
|
+
def entry_form(*attrs, &block)
|
10
|
+
options = attrs.extract_options!
|
11
|
+
attrs = default_attrs - [:created_at, :updated_at] if attrs.blank?
|
12
|
+
attrs << options
|
13
|
+
crud_form(path_args(entry), *attrs, &block)
|
13
14
|
end
|
14
15
|
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
# Renders a standard form for the given entry and attributes.
|
17
|
+
# The form is rendered with a basic save and cancel button.
|
18
|
+
# If a block is given, custom input fields may be rendered and attrs is ignored.
|
19
|
+
# An options hash may be given as the last argument.
|
20
|
+
def crud_form(object, *attrs, &block)
|
21
|
+
options = attrs.extract_options!
|
22
|
+
cancel_url = get_cancel_url(object, options)
|
23
|
+
|
24
|
+
standard_form(object, options) do |form|
|
25
|
+
content = if block_given?
|
26
|
+
capture(form, &block)
|
27
|
+
else
|
28
|
+
form.labeled_input_fields(*attrs)
|
25
29
|
end
|
30
|
+
|
31
|
+
content << form.standard_actions(cancel_url)
|
32
|
+
content.html_safe
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create a table of the current entries with the default or the passed
|
37
|
+
# attributes in its columns.
|
38
|
+
# If attrs are present, the first column will link to the show
|
39
|
+
# action. Edit and destroy actions are appended to the end of each row.
|
40
|
+
# If a block is given, the column defined there will be inserted
|
41
|
+
# between the given attributes and the actions.
|
42
|
+
# An options hash for the table builder may be given as the last argument.
|
43
|
+
def crud_table(*attrs, &block)
|
44
|
+
options = attrs.extract_options!
|
45
|
+
attributes = (block_given? || attrs.present?) ? attrs : default_attrs
|
46
|
+
first = attributes.shift
|
47
|
+
table(entries, options) do |t|
|
48
|
+
col_show(t, first) if first
|
49
|
+
t.sortable_attrs(*attributes)
|
50
|
+
yield t if block_given?
|
51
|
+
add_table_actions(t)
|
26
52
|
end
|
27
53
|
end
|
28
54
|
|
29
55
|
# Adds a set of standard action link column (show, edit, destroy) to the given table.
|
30
56
|
def add_table_actions(table)
|
31
|
-
action_col_show(table)
|
32
57
|
action_col_edit(table)
|
33
58
|
action_col_destroy(table)
|
34
59
|
end
|
60
|
+
|
61
|
+
# Renders the passed attr with a link to the show action for
|
62
|
+
# the current entry.
|
63
|
+
# A block may be given to define the link path for the row entry.
|
64
|
+
def col_show(table, attr, &block)
|
65
|
+
table.attr(attr, table.sort_header(attr)) do |e|
|
66
|
+
link_to(format_attr(e, attr), action_path(e, &block))
|
67
|
+
end
|
68
|
+
end
|
35
69
|
|
36
70
|
# Action link to show the row entry inside a table.
|
37
71
|
# A block may be given to define the link path for the row entry.
|
38
72
|
def action_col_show(table, &block)
|
39
|
-
action_col(table)
|
73
|
+
action_col(table) do |e|
|
74
|
+
link_table_action('zoom-in', action_path(e, &block))
|
75
|
+
end
|
40
76
|
end
|
41
77
|
|
42
78
|
# Action link to edit inside a table.
|
@@ -53,8 +89,8 @@ module CrudHelper
|
|
53
89
|
def action_col_destroy(table, &block)
|
54
90
|
action_col(table) do |e|
|
55
91
|
link_table_action('remove', action_path(e, &block),
|
56
|
-
:confirm => ti(:confirm_delete),
|
57
|
-
|
92
|
+
:data => { :confirm => ti(:confirm_delete),
|
93
|
+
:method => :delete })
|
58
94
|
end
|
59
95
|
end
|
60
96
|
|
@@ -90,8 +126,8 @@ module CrudHelper
|
|
90
126
|
def link_action_destroy(path = nil)
|
91
127
|
path ||= path_args(entry)
|
92
128
|
link_action ti(:"link.delete"), 'remove', path,
|
93
|
-
:confirm => ti(:confirm_delete),
|
94
|
-
|
129
|
+
:data => { :confirm => ti(:confirm_delete),
|
130
|
+
:method => :delete }
|
95
131
|
end
|
96
132
|
|
97
133
|
# Standard link action to the list page.
|
@@ -110,17 +146,23 @@ module CrudHelper
|
|
110
146
|
|
111
147
|
private
|
112
148
|
|
149
|
+
# Get the cancel url for the given object considering options:
|
150
|
+
# 1. Use :cancel_url_new or :cancel_url_edit option, if present
|
151
|
+
# 2. Use :cancel_url option, if present
|
152
|
+
# 3. Use polymorphic_path(object)
|
153
|
+
def get_cancel_url(object, options)
|
154
|
+
record = Array(object).last
|
155
|
+
cancel_url = options.delete(:cancel_url)
|
156
|
+
cancel_url_new = options.delete(:cancel_url_new)
|
157
|
+
cancel_url_edit = options.delete(:cancel_url_edit)
|
158
|
+
url = record.new_record? ? cancel_url_new : cancel_url_edit
|
159
|
+
url || cancel_url || polymorphic_path(object, :returning => true)
|
160
|
+
end
|
161
|
+
|
113
162
|
# If a block is given, call it to get the path for the current row entry.
|
114
163
|
# Otherwise, return the standard path args.
|
115
164
|
def action_path(e, &block)
|
116
165
|
block_given? ? yield(e) : path_args(e)
|
117
166
|
end
|
118
167
|
|
119
|
-
# Returns default attrs for a crud table if no others are passed.
|
120
|
-
def attrs_or_default(attrs)
|
121
|
-
options = attrs.extract_options!
|
122
|
-
attrs = yield if attrs.blank?
|
123
|
-
attrs << options
|
124
|
-
end
|
125
|
-
|
126
168
|
end
|
@@ -9,7 +9,7 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
9
9
|
|
10
10
|
attr_reader :template
|
11
11
|
|
12
|
-
delegate :association, :column_type, :column_property, :captionize, :ta,
|
12
|
+
delegate :association, :column_type, :column_property, :captionize, :ti, :ta, :link_to,
|
13
13
|
:content_tag, :safe_join, :capture, :add_css_class, :assoc_and_id_attr,
|
14
14
|
:to => :template
|
15
15
|
|
@@ -121,6 +121,28 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
121
121
|
add_css_class(html_options, 'multiselect')
|
122
122
|
belongs_to_field(attr, html_options)
|
123
123
|
end
|
124
|
+
|
125
|
+
# Render the error messages for the current form.
|
126
|
+
def error_messages
|
127
|
+
@template.render('shared/error_messages', :errors => @object.errors, :object => @object)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Render a submit button and a cancel link for this form.
|
131
|
+
def standard_actions(cancel_url, submit_label = ti(:"button.save"))
|
132
|
+
content_tag(:div, :class => 'form-actions') do
|
133
|
+
safe_join([submit_button(submit_label), cancel_link(cancel_url)], ' ')
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Render a standard submit button with the given label.
|
138
|
+
def submit_button(label = ti(:"button.save"))
|
139
|
+
button(label, :class => 'btn btn-primary')
|
140
|
+
end
|
141
|
+
|
142
|
+
# Render a cancel link pointing to the given url.
|
143
|
+
def cancel_link(url)
|
144
|
+
link_to(ti(:"button.cancel"), url, :class => 'cancel')
|
145
|
+
end
|
124
146
|
|
125
147
|
# Renders a marker if the given attr has to be present.
|
126
148
|
def required_mark(attr)
|
@@ -158,9 +180,11 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
158
180
|
|
159
181
|
# Dispatch methods starting with 'labeled_' to render a label and the corresponding
|
160
182
|
# input field. E.g. labeled_boolean_field(:checked, :class => 'bold')
|
183
|
+
# To add an additional help text, use the help option.
|
184
|
+
# E.g. labeled_boolean_field(:checked, :help => 'Some Help')
|
161
185
|
def method_missing(name, *args)
|
162
186
|
if field_method = labeled_field_method?(name)
|
163
|
-
|
187
|
+
build_labeled_field(field_method, *args)
|
164
188
|
else
|
165
189
|
super(name, *args)
|
166
190
|
end
|
@@ -171,7 +195,12 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
171
195
|
labeled_field_method?(name).present? || super(name)
|
172
196
|
end
|
173
197
|
|
174
|
-
|
198
|
+
# Generates a help block for fields
|
199
|
+
def help_block(text)
|
200
|
+
content_tag(:p, text, :class => 'help-block')
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
175
204
|
|
176
205
|
# Returns true if attr is a non-polymorphic association.
|
177
206
|
# If one or more macros are given, the association must be of this kind.
|
@@ -221,4 +250,12 @@ class StandardFormBuilder < ActionView::Helpers::FormBuilder
|
|
221
250
|
end
|
222
251
|
end
|
223
252
|
|
253
|
+
def build_labeled_field(field_method, *args)
|
254
|
+
options = args.extract_options!
|
255
|
+
help = options.delete(:help)
|
256
|
+
text = send(field_method, *(args<<options)) + required_mark(args.first)
|
257
|
+
text << help_block(help) if help.present?
|
258
|
+
labeled(args.first, text)
|
259
|
+
end
|
260
|
+
|
224
261
|
end
|
@@ -11,7 +11,8 @@ module StandardHelper
|
|
11
11
|
def f(value)
|
12
12
|
case value
|
13
13
|
when Fixnum then number_with_delimiter(value)
|
14
|
-
when Float, BigDecimal then number_with_precision(value, :precision =>
|
14
|
+
when Float, BigDecimal then number_with_precision(value, :precision => t('number.format.precision'),
|
15
|
+
:delimiter => t('number.format.delimiter'))
|
15
16
|
when Date then l(value)
|
16
17
|
when Time then l(value, :format => :time)
|
17
18
|
when true then t(:"global.yes")
|
@@ -78,6 +79,7 @@ module StandardHelper
|
|
78
79
|
# If entries is empty, an appropriate message is rendered.
|
79
80
|
# An options hash may be given as the last argument.
|
80
81
|
def table(entries, *attrs, &block)
|
82
|
+
entries.inspect # force evaluation of relations
|
81
83
|
if entries.present?
|
82
84
|
StandardTableBuilder.table(entries, self, attrs.extract_options!) do |t|
|
83
85
|
t.attrs(*attrs)
|
@@ -88,40 +90,19 @@ module StandardHelper
|
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
91
|
-
# Renders a
|
93
|
+
# Renders a standard form using StandardFormBuilder.
|
92
94
|
# Before the input fields, the error messages are rendered, if present.
|
93
|
-
|
94
|
-
# If a block is given, custom input fields may be rendered and attrs is ignored.
|
95
|
-
# An options hash may be given as the last argument.
|
96
|
-
def standard_form(object, *attrs, &block)
|
97
|
-
options = attrs.extract_options!
|
95
|
+
def standard_form(object, options = {}, &block)
|
98
96
|
options[:builder] ||= StandardFormBuilder
|
99
97
|
options[:html] ||= {}
|
100
98
|
add_css_class options[:html], 'form-horizontal'
|
101
99
|
|
102
100
|
form_for(object, options) do |form|
|
103
|
-
|
104
|
-
content
|
105
|
-
|
106
|
-
content << if block_given?
|
107
|
-
capture(form, &block)
|
108
|
-
else
|
109
|
-
form.labeled_input_fields(*attrs)
|
110
|
-
end
|
111
|
-
|
112
|
-
content << content_tag(:div, :class => 'form-actions') do
|
113
|
-
form.button(ti(:"button.save"), :class => 'btn btn-primary') +
|
114
|
-
' ' +
|
115
|
-
cancel_link(object)
|
116
|
-
end
|
117
|
-
content.html_safe
|
101
|
+
content = form.error_messages
|
102
|
+
content << capture(form, &block)
|
118
103
|
end
|
119
104
|
end
|
120
105
|
|
121
|
-
def cancel_link(object)
|
122
|
-
link_to(ti(:"button.cancel"), polymorphic_path(object, :returning => true), :class => 'cancel')
|
123
|
-
end
|
124
|
-
|
125
106
|
# Renders a simple unordered list, which will
|
126
107
|
# simply render all passed items or yield them
|
127
108
|
# to your block.
|
@@ -230,7 +211,7 @@ module StandardHelper
|
|
230
211
|
end
|
231
212
|
end
|
232
213
|
|
233
|
-
|
214
|
+
private
|
234
215
|
|
235
216
|
# Helper methods that are not directly called from templates.
|
236
217
|
|