mack-data_mapper 0.5.5 → 0.6.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 +6 -0
- data/lib/database.rb +94 -0
- data/lib/dm_patches/confirmation_validation.rb +19 -0
- data/lib/dm_patches/dm-cli.rb +1 -0
- data/lib/dm_patches/migrations.rb +23 -0
- data/lib/dm_patches/pooling.rb +229 -0
- data/lib/genosaurus_helpers.rb +40 -0
- data/lib/helpers/orm_helpers.rb +50 -21
- data/lib/mack-data_mapper.rb +43 -16
- data/lib/migration_generator/migration_generator.rb +28 -17
- data/lib/migration_generator/templates/db/migrations/%=@migration_name%.rb.template +6 -6
- data/lib/model_column.rb +42 -0
- data/lib/model_generator/manifest.yml +9 -2
- data/lib/model_generator/model_generator.rb +25 -20
- data/lib/model_generator/templates/model.rb.template +4 -4
- data/lib/model_generator/templates/rspec.rb.template +7 -0
- data/lib/model_generator/templates/{test.rb.template → test_case.rb.template} +0 -0
- data/lib/resource.rb +17 -0
- data/lib/runner.rb +17 -0
- data/lib/scaffold_generator/manifest.yml +14 -3
- data/lib/scaffold_generator/scaffold_generator.rb +4 -4
- data/lib/scaffold_generator/templates/app/controllers/controller.rb.template +10 -9
- data/lib/scaffold_generator/templates/app/helpers/controllers/helper.rb.template +7 -0
- data/lib/scaffold_generator/templates/app/views/edit.html.erb.template +1 -1
- data/lib/scaffold_generator/templates/app/views/new.html.erb.template +1 -1
- data/lib/scaffold_generator/templates/test/functional/rspec.rb.template +47 -0
- data/lib/scaffold_generator/templates/{test.rb.template → test/functional/test_case.rb.template} +0 -0
- data/lib/tasks/db_create_drop_tasks.rake +43 -62
- data/lib/tasks/db_migration_tasks.rake +25 -62
- data/lib/tasks/test_tasks.rake +12 -0
- data/lib/test_extensions.rb +90 -0
- metadata +28 -52
- data/lib/configuration.rb +0 -22
- data/lib/persistence.rb +0 -9
- data/test/database.yml +0 -3
- data/test/fixtures/add_users_migration.rb.fixture +0 -9
- data/test/fixtures/album.rb.fixture +0 -4
- data/test/fixtures/album_unit_test.rb.fixture +0 -9
- data/test/fixtures/album_with_cols.rb.fixture +0 -7
- data/test/fixtures/create_users_migration.rb.fixture +0 -12
- data/test/fixtures/routes.rb.fixture +0 -3
- data/test/fixtures/zoo_no_cols/edit.html.erb.fixture +0 -11
- data/test/fixtures/zoo_no_cols/index.html.erb.fixture +0 -20
- data/test/fixtures/zoo_no_cols/new.html.erb.fixture +0 -11
- data/test/fixtures/zoo_no_cols/show.html.erb.fixture +0 -6
- data/test/fixtures/zoo_with_cols/edit.html.erb.fixture +0 -19
- data/test/fixtures/zoo_with_cols/index.html.erb.fixture +0 -26
- data/test/fixtures/zoo_with_cols/new.html.erb.fixture +0 -19
- data/test/fixtures/zoo_with_cols/show.html.erb.fixture +0 -22
- data/test/fixtures/zoo_with_cols/zoo.rb.fixture +0 -4
- data/test/fixtures/zoo_with_cols/zoos_controller.rb.fixture +0 -50
- data/test/generators/migration_generator_test.rb +0 -71
- data/test/generators/model_generator_test.rb +0 -37
- data/test/generators/scaffold_generator_test.rb +0 -61
- data/test/lib/user.rb +0 -6
- data/test/tasks/db_migration_tasks_test.rb +0 -57
- data/test/test_helper.rb +0 -77
data/README
CHANGED
@@ -1,3 +1,9 @@
|
|
1
1
|
README
|
2
2
|
========================================================================
|
3
3
|
mack-data_mapper was developed by: markbates
|
4
|
+
|
5
|
+
This gem provides Mack integration with the ORM Framework, DataMapper.
|
6
|
+
|
7
|
+
For more information on DataMapper please visit:
|
8
|
+
|
9
|
+
http://www.datamapper.org
|
data/lib/database.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module Mack
|
2
|
+
module Database
|
3
|
+
|
4
|
+
# Sets up and establishes connections to the database based on the specified environment
|
5
|
+
# and the settings in the database.yml file.
|
6
|
+
def self.establish_connection(env = Mack.env)
|
7
|
+
dbs = YAML::load(ERB.new(IO.read(File.join(Mack.root, "config", "database.yml"))).result)
|
8
|
+
settings = dbs[env]
|
9
|
+
settings.symbolize_keys!
|
10
|
+
if settings[:default]
|
11
|
+
settings.each do |k,v|
|
12
|
+
DataMapper.setup(k, v.symbolize_keys)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
DataMapper.setup(:default, settings)
|
16
|
+
end
|
17
|
+
end # establish_connection
|
18
|
+
|
19
|
+
# Creates a database, if it doesn't already exist for the specified environment
|
20
|
+
def self.create(env = Mack.env, repis = :default)
|
21
|
+
Mack::Database.establish_connection(env)
|
22
|
+
create_database(repis)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Drops a database, if it exists for the specified environment
|
26
|
+
def self.drop(env = Mack.env, repis = :default)
|
27
|
+
Mack::Database.establish_connection(env)
|
28
|
+
drop_database(repis)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def self.setup_temp(uri, adapter)
|
33
|
+
DataMapper.setup(:tmp, {
|
34
|
+
:adapter => adapter,
|
35
|
+
:host => "localhost",
|
36
|
+
:database => adapter,
|
37
|
+
:username => ENV["DB_USERNAME"] || uri.user,
|
38
|
+
:password => ENV["DB_PASSWORD"] || uri.password
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.create_database(repis = :default)
|
43
|
+
uri = repository(repis).adapter.uri
|
44
|
+
case repository(repis).adapter.class.name
|
45
|
+
when /Mysql/
|
46
|
+
setup_temp(uri, "mysql")
|
47
|
+
repository(:tmp) do |repo|
|
48
|
+
puts "Creating (MySQL): #{uri.basename}"
|
49
|
+
repo.adapter.execute "CREATE DATABASE `#{uri.basename}` DEFAULT CHARACTER SET `utf8`"
|
50
|
+
end
|
51
|
+
when /Postgres/
|
52
|
+
setup_temp(uri, "postgres")
|
53
|
+
repository(:tmp) do |repo|
|
54
|
+
puts "Creating (PostgreSQL): #{uri.basename}"
|
55
|
+
repo.adapter.execute "CREATE DATABASE #{uri.basename} ENCODING = 'utf8'"
|
56
|
+
end
|
57
|
+
when /Sqlite3/
|
58
|
+
db_dir = File.join(Mack.root, "db")
|
59
|
+
puts "Creating (SQLite3): #{uri.basename}"
|
60
|
+
FileUtils.mkdir_p(db_dir)
|
61
|
+
FileUtils.touch(File.join(db_dir, uri.basename))
|
62
|
+
else
|
63
|
+
raise "Task not supported for '#{repository(repis).adapter.class.name}'"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def self.drop_database(repis = :default)
|
69
|
+
uri = repository(repis).adapter.uri
|
70
|
+
case repository(repis).adapter.class.name
|
71
|
+
when /Mysql/
|
72
|
+
setup_temp(uri, "mysql")
|
73
|
+
repository(:tmp) do |repo|
|
74
|
+
puts "Dropping (MySQL): #{uri.basename}"
|
75
|
+
repo.adapter.execute "DROP DATABASE IF EXISTS `#{uri.basename}`"
|
76
|
+
end
|
77
|
+
when /Postgres/
|
78
|
+
setup_temp(uri, "postgres")
|
79
|
+
repository(:tmp) do |repo|
|
80
|
+
puts "Dropping (PostgreSQL): #{uri.basename}"
|
81
|
+
repo.adapter.execute "DROP DATABASE IF EXISTS #{uri.basename}"
|
82
|
+
end
|
83
|
+
when /Sqlite3/
|
84
|
+
puts "Dropping (SQLite3): #{uri.basename}"
|
85
|
+
db_dir = File.join(Mack.root, "db")
|
86
|
+
FileUtils.rm_rf(File.join(db_dir.to_s, uri.basename))
|
87
|
+
else
|
88
|
+
raise "Task not supported for '#{repository(repis).adapter.class.name}'"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end # Database
|
93
|
+
|
94
|
+
end # Mack
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DataMapper # :nodoc:
|
2
|
+
module Validate # :nodoc:
|
3
|
+
|
4
|
+
class ConfirmationValidator < GenericValidator # :nodoc:
|
5
|
+
|
6
|
+
def valid?(target)
|
7
|
+
field_value = target.instance_variable_get("@#{@field_name}")
|
8
|
+
return true if @options[:allow_nil] && field_value.nil?
|
9
|
+
return false if !@options[:allow_nil] && field_value.nil?
|
10
|
+
return true unless target.attribute_dirty?(@field_name)
|
11
|
+
|
12
|
+
confirm_value = target.instance_variable_get("@#{@confirm_field_name}")
|
13
|
+
field_value == confirm_value
|
14
|
+
end
|
15
|
+
|
16
|
+
end # class ConfirmationValidator
|
17
|
+
|
18
|
+
end # module Validate
|
19
|
+
end # module DataMapper
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'data_mapper/cli'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DataMapper # :nodoc:
|
2
|
+
module MigrationRunner # :nodoc:
|
3
|
+
|
4
|
+
def reset!
|
5
|
+
@@migrations = []
|
6
|
+
end
|
7
|
+
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module SQL # :nodoc:
|
12
|
+
class TableCreator # :nodoc:
|
13
|
+
class Column # :nodoc:
|
14
|
+
|
15
|
+
def build_type(type_class)
|
16
|
+
schema = {:name => @name, :quote_column_name => quoted_name}.merge(@opts)
|
17
|
+
schema = @adapter.class.type_map[type_class].merge(schema)
|
18
|
+
@adapter.property_schema_statement(schema)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Extlib # :nodoc:
|
5
|
+
# ==== Notes
|
6
|
+
# Provides pooling support to class it got included in.
|
7
|
+
#
|
8
|
+
# Pooling of objects is a faster way of aquiring instances
|
9
|
+
# of objects compared to regular allocation and initialization
|
10
|
+
# because instances are keeped in memory reused.
|
11
|
+
#
|
12
|
+
# Classes that include Pooling module have re-defined new
|
13
|
+
# method that returns instances acquired from pool.
|
14
|
+
#
|
15
|
+
# Term resource is used for any type of poolable objects
|
16
|
+
# and should NOT be thought as DataMapper Resource or
|
17
|
+
# ActiveResource resource and such.
|
18
|
+
#
|
19
|
+
# In Data Objects connections are pooled so that it is
|
20
|
+
# unnecessary to allocate and initialize connection object
|
21
|
+
# each time connection is needed, like per request in a
|
22
|
+
# web application.
|
23
|
+
#
|
24
|
+
# Pool obviously has to be thread safe because state of
|
25
|
+
# object is reset when it is released.
|
26
|
+
module Pooling # :nodoc:
|
27
|
+
|
28
|
+
def self.scavenger
|
29
|
+
@scavenger || begin
|
30
|
+
@scavenger = Thread.new do
|
31
|
+
loop do
|
32
|
+
lock.synchronize do
|
33
|
+
pools.each do |pool|
|
34
|
+
# This is a useful check, but non-essential, and right now it breaks lots of stuff.
|
35
|
+
# if pool.expired?
|
36
|
+
pool.lock.synchronize do
|
37
|
+
if pool.reserved_count == 0
|
38
|
+
pool.dispose
|
39
|
+
end
|
40
|
+
end
|
41
|
+
# end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
sleep(scavenger_interval)
|
45
|
+
end # loop
|
46
|
+
end
|
47
|
+
|
48
|
+
@scavenger.priority = -10
|
49
|
+
@scavenger
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.pools
|
54
|
+
@pools ||= Set.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.append_pool(pool)
|
58
|
+
lock.synchronize do
|
59
|
+
pools << pool
|
60
|
+
end
|
61
|
+
Extlib::Pooling::scavenger
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.lock
|
65
|
+
@lock ||= Mutex.new
|
66
|
+
end
|
67
|
+
|
68
|
+
class CrossPoolError < StandardError # :nodoc:
|
69
|
+
end
|
70
|
+
|
71
|
+
class OrphanedObjectError < StandardError # :nodoc:
|
72
|
+
end
|
73
|
+
|
74
|
+
class ThreadStopError < StandardError # :nodoc:
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.included(target)
|
78
|
+
target.class_eval do
|
79
|
+
class << self
|
80
|
+
alias __new new
|
81
|
+
end
|
82
|
+
|
83
|
+
@__pools = Hash.new { |h,k| __pool_lock.synchronize { h[k] = Pool.new(target.pool_size, target, k) } }
|
84
|
+
@__pool_lock = Mutex.new
|
85
|
+
|
86
|
+
def self.__pool_lock
|
87
|
+
@__pool_lock
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.new(*args)
|
91
|
+
@__pools[args].new
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.__pools
|
95
|
+
@__pools
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.pool_size
|
99
|
+
8
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def release
|
105
|
+
@__pool.release(self)
|
106
|
+
end
|
107
|
+
|
108
|
+
class Pool # :nodoc:
|
109
|
+
def initialize(max_size, resource, args)
|
110
|
+
raise ArgumentError.new("+max_size+ should be a Fixnum but was #{max_size.inspect}") unless Fixnum === max_size
|
111
|
+
raise ArgumentError.new("+resource+ should be a Class but was #{resource.inspect}") unless Class === resource
|
112
|
+
|
113
|
+
@max_size = max_size
|
114
|
+
@resource = resource
|
115
|
+
@args = args
|
116
|
+
|
117
|
+
@available = []
|
118
|
+
@reserved_count = 0
|
119
|
+
end
|
120
|
+
|
121
|
+
def lock
|
122
|
+
@resource.__pool_lock
|
123
|
+
end
|
124
|
+
|
125
|
+
def scavenge_interval
|
126
|
+
@resource.scavenge_interval
|
127
|
+
end
|
128
|
+
|
129
|
+
def new
|
130
|
+
instance = nil
|
131
|
+
|
132
|
+
lock.synchronize do
|
133
|
+
instance = acquire
|
134
|
+
end
|
135
|
+
|
136
|
+
Extlib::Pooling::append_pool(self)
|
137
|
+
|
138
|
+
if instance.nil?
|
139
|
+
# Account for the current thread, and the pool scavenger.
|
140
|
+
if ThreadGroup::Default.list.size == 2 && @reserved_count >= @max_size
|
141
|
+
raise ThreadStopError.new(size)
|
142
|
+
else
|
143
|
+
sleep(0.05)
|
144
|
+
new
|
145
|
+
end
|
146
|
+
else
|
147
|
+
instance
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def release(instance)
|
152
|
+
lock.synchronize do
|
153
|
+
instance.instance_variable_set(:@__pool, nil)
|
154
|
+
@reserved_count -= 1
|
155
|
+
@available.push(instance)
|
156
|
+
end
|
157
|
+
nil
|
158
|
+
end
|
159
|
+
|
160
|
+
def size
|
161
|
+
@available.size + @reserved_count
|
162
|
+
end
|
163
|
+
alias length size
|
164
|
+
|
165
|
+
def inspect
|
166
|
+
"#<Extlib::Pooling::Pool<#{@resource.name}> available=#{@available.size} reserved_count=#{@reserved_count}>"
|
167
|
+
end
|
168
|
+
|
169
|
+
def flush!
|
170
|
+
until @available.empty?
|
171
|
+
instance = @available.pop
|
172
|
+
instance.dispose
|
173
|
+
end
|
174
|
+
@available.clear
|
175
|
+
end
|
176
|
+
|
177
|
+
def dispose
|
178
|
+
flush!
|
179
|
+
@resource.__pools.delete(@args)
|
180
|
+
!Extlib::Pooling::pools.delete?(self).nil?
|
181
|
+
end
|
182
|
+
|
183
|
+
# Disabled temporarily.
|
184
|
+
#
|
185
|
+
# def expired?
|
186
|
+
# lock.synchronize do
|
187
|
+
# @available.each do |instance|
|
188
|
+
# if instance.instance_variable_get(:@__allocated_in_pool) + scavenge_interval < Time.now
|
189
|
+
# instance.dispose
|
190
|
+
# @available.delete(instance)
|
191
|
+
# end
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# size == 0
|
195
|
+
# end
|
196
|
+
# end
|
197
|
+
|
198
|
+
def reserved_count
|
199
|
+
@reserved_count
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
def acquire
|
205
|
+
instance = if !@available.empty?
|
206
|
+
@available.pop
|
207
|
+
elsif size < @max_size
|
208
|
+
@resource.__new(*@args)
|
209
|
+
else
|
210
|
+
nil
|
211
|
+
end
|
212
|
+
|
213
|
+
if instance.nil?
|
214
|
+
instance
|
215
|
+
else
|
216
|
+
raise CrossPoolError.new(instance) if instance.instance_variable_get(:@__pool)
|
217
|
+
@reserved_count += 1
|
218
|
+
instance.instance_variable_set(:@__pool, self)
|
219
|
+
instance.instance_variable_set(:@__allocated_in_pool, Time.now)
|
220
|
+
instance
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.scavenger_interval
|
226
|
+
60
|
227
|
+
end
|
228
|
+
end # module Pooling
|
229
|
+
end # module Extlib
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Mack
|
2
|
+
module Genosaurus # :nodoc:
|
3
|
+
module DataMapper # :nodoc:
|
4
|
+
module Helpers
|
5
|
+
|
6
|
+
def columns(name = param(:name))
|
7
|
+
ivar_cache("form_columns") do
|
8
|
+
cs = []
|
9
|
+
cols = (param(:cols) || param(:columns))
|
10
|
+
if cols
|
11
|
+
cols.split(",").each do |x|
|
12
|
+
cs << Mack::Genosaurus::DataMapper::ModelColumn.new(name, x)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
cs
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def db_directory
|
20
|
+
File.join(Mack.root, "db")
|
21
|
+
end
|
22
|
+
|
23
|
+
def migrations_directory
|
24
|
+
File.join(db_directory, "migrations")
|
25
|
+
end
|
26
|
+
|
27
|
+
def next_migration_number
|
28
|
+
last = Dir.glob(File.join(migrations_directory, "*.rb")).last
|
29
|
+
if last
|
30
|
+
return File.basename(last).match(/^\d+/).to_s.succ
|
31
|
+
end
|
32
|
+
return "001"
|
33
|
+
end
|
34
|
+
|
35
|
+
::Genosaurus.send(:include, self)
|
36
|
+
|
37
|
+
end # Helpers
|
38
|
+
end # DataMapper
|
39
|
+
end # Genosaurus
|
40
|
+
end # Mack
|
data/lib/helpers/orm_helpers.rb
CHANGED
@@ -1,47 +1,76 @@
|
|
1
1
|
module Mack
|
2
|
-
module ViewHelpers
|
3
|
-
module
|
2
|
+
module ViewHelpers # :nodoc:
|
3
|
+
module DataMapperHelpers
|
4
|
+
|
4
5
|
DEFAULT_PARTIAL = %{
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
}
|
16
|
-
|
6
|
+
<div>
|
7
|
+
<div class="errorExplanation" id="errorExplanation">
|
8
|
+
<h2><%= pluralize_word(errors.size, "error") %> occured.</h2>
|
9
|
+
<ul>
|
10
|
+
<% for error in errors %>
|
11
|
+
<li><%= error %></li>
|
12
|
+
<% end %>
|
13
|
+
</ul>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
} unless Mack::ViewHelpers::DataMapperHelpers.const_defined?("DEFAULT_PARTIAL")
|
17
|
+
|
18
|
+
# Provides view level support for printing out all the errors associated with the
|
19
|
+
# models you tell it.
|
20
|
+
# The DEFAULT_PARTIAL constant provides a simple, default, set of HTML for displaying
|
21
|
+
# the errors. If you wish to change this HTML there are two simple ways of doing it.
|
22
|
+
# First if you have a partial named: app/views/application/_error_messages.html.erb,
|
23
|
+
# then it will use that default, and not DEFAULT_PARTIAL. The other option is to pass
|
24
|
+
# in a path to partial as the second argument and that partial will be rendered.
|
17
25
|
def error_messages_for(object_names = [], view_partial = nil)
|
18
26
|
object_names = [object_names].flatten
|
19
27
|
app_errors = []
|
20
28
|
object_names.each do |name|
|
21
29
|
object = instance_variable_get("@#{name}")
|
22
30
|
if object
|
23
|
-
if object.is_a?(DataMapper::
|
24
|
-
app_errors << object.errors.full_messages
|
31
|
+
if object.is_a?(DataMapper::Resource)
|
32
|
+
app_errors << object.errors.full_messages.uniq
|
25
33
|
end
|
26
34
|
end
|
27
35
|
end
|
28
36
|
app_errors.flatten!
|
29
|
-
File.join(Mack::Configuration.views_directory, "application", "_error_messages.html.erb")
|
30
37
|
unless app_errors.empty?
|
31
38
|
if view_partial.nil?
|
32
|
-
if File.exist?(File.join(Mack
|
39
|
+
if File.exist?(File.join(Mack.root, "app", "views", "application", "_error_messages.html.erb"))
|
33
40
|
render(:partial, "application/error_messages", :locals => {:errors => app_errors})
|
34
41
|
else
|
35
|
-
render(:
|
42
|
+
render(:inline, DEFAULT_PARTIAL, :locals => {:errors => app_errors})
|
36
43
|
end
|
37
|
-
else
|
44
|
+
else
|
38
45
|
render(:partial, view_partial, :locals => {:errors => app_errors})
|
39
46
|
end
|
40
47
|
else
|
41
48
|
""
|
42
49
|
end
|
43
50
|
end
|
44
|
-
|
51
|
+
|
52
|
+
# Generates a text input tag for a given model and field
|
53
|
+
#
|
54
|
+
# Example:
|
55
|
+
# model_text_field(@user, :username) # => <input id="user_username" name="user[username]" type="text" value="<@user.username's value>" />
|
56
|
+
def model_text_field(model, property, options = {})
|
57
|
+
m_name = model.class.to_s.underscore
|
58
|
+
non_content_tag(:input, {:type => :text, :name => "#{m_name}[#{property}]", :id => "#{m_name}_#{property}", :value => model.send(property)}.merge(options))
|
59
|
+
end
|
60
|
+
|
61
|
+
# Generates a password input tag for a given model and field
|
62
|
+
#
|
63
|
+
# Example:
|
64
|
+
# model_password_field(@user, :password) # => <input id="user_username" name="user[username]" type="password" value="<@user.username's value>" />
|
65
|
+
def model_password_field(model, property, options = {})
|
66
|
+
model_text_field(model, property, {:type => :password}.merge(options))
|
67
|
+
end
|
68
|
+
|
69
|
+
def model_textarea(model, property, options = {})
|
70
|
+
m_name = model.class.to_s.underscore
|
71
|
+
content_tag(:textarea, {:name => "#{m_name}[#{property}]", :id => "#{m_name}_#{property}", :cols => 60, :rows => 20}.merge(options), model.send(property))
|
72
|
+
end
|
73
|
+
|
45
74
|
end # OrmHelpers
|
46
75
|
end # ViewHelpers
|
47
76
|
end # Mack
|