mack-data_mapper 0.5.5 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|