mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add attachment and attachments field generators
This commit is contained in:
parent
4e076b03b6
commit
ecdcf06cb2
13 changed files with 130 additions and 25 deletions
|
@ -6,6 +6,12 @@ class <%= class_name %> < <%= parent_class_name.classify %>
|
||||||
<% attributes.select(&:rich_text?).each do |attribute| -%>
|
<% attributes.select(&:rich_text?).each do |attribute| -%>
|
||||||
has_rich_text :<%= attribute.name %>
|
has_rich_text :<%= attribute.name %>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
|
<% attributes.select(&:attachment?).each do |attribute| -%>
|
||||||
|
has_one_attached :<%= attribute.name %>
|
||||||
|
<% end -%>
|
||||||
|
<% attributes.select(&:attachments?).each do |attribute| -%>
|
||||||
|
has_many_attached :<%= attribute.name %>
|
||||||
|
<% end -%>
|
||||||
<% attributes.select(&:token?).each do |attribute| -%>
|
<% attributes.select(&:token?).each do |attribute| -%>
|
||||||
has_secure_token<% if attribute.name != "token" %> :<%= attribute.name %><% end %>
|
has_secure_token<% if attribute.name != "token" %> :<%= attribute.name %><% end %>
|
||||||
<% end -%>
|
<% end -%>
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<%%= form.label :password_confirmation %>
|
<%%= form.label :password_confirmation %>
|
||||||
<%%= form.password_field :password_confirmation %>
|
<%%= form.password_field :password_confirmation %>
|
||||||
|
<% elsif attribute.attachments? -%>
|
||||||
|
<%%= form.label :<%= attribute.column_name %> %>
|
||||||
|
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, multiple: true %>
|
||||||
<% else -%>
|
<% else -%>
|
||||||
<%%= form.label :<%= attribute.column_name %> %>
|
<%%= form.label :<%= attribute.column_name %> %>
|
||||||
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %> %>
|
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %> %>
|
||||||
|
|
|
@ -3,7 +3,15 @@
|
||||||
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
||||||
<p>
|
<p>
|
||||||
<strong><%= attribute.human_name %>:</strong>
|
<strong><%= attribute.human_name %>:</strong>
|
||||||
|
<% if attribute.attachment? -%>
|
||||||
|
<%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> %>
|
||||||
|
<% elsif attribute.attachments? -%>
|
||||||
|
<%% @<%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
|
||||||
|
<div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div>
|
||||||
|
<%% end %>
|
||||||
|
<% else -%>
|
||||||
<%%= @<%= singular_table_name %>.<%= attribute.column_name %> %>
|
<%%= @<%= singular_table_name %>.<%= attribute.column_name %> %>
|
||||||
|
<% end -%>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<% end -%>
|
<% end -%>
|
||||||
|
|
|
@ -68,14 +68,15 @@ module Rails
|
||||||
|
|
||||||
def field_type
|
def field_type
|
||||||
@field_type ||= case type
|
@field_type ||= case type
|
||||||
when :integer then :number_field
|
when :integer then :number_field
|
||||||
when :float, :decimal then :text_field
|
when :float, :decimal then :text_field
|
||||||
when :time then :time_select
|
when :time then :time_select
|
||||||
when :datetime, :timestamp then :datetime_select
|
when :datetime, :timestamp then :datetime_select
|
||||||
when :date then :date_select
|
when :date then :date_select
|
||||||
when :text then :text_area
|
when :text then :text_area
|
||||||
when :rich_text then :rich_text_area
|
when :rich_text then :rich_text_area
|
||||||
when :boolean then :check_box
|
when :boolean then :check_box
|
||||||
|
when :attachment, :attachments then :file_field
|
||||||
else
|
else
|
||||||
:text_field
|
:text_field
|
||||||
end
|
end
|
||||||
|
@ -83,15 +84,17 @@ module Rails
|
||||||
|
|
||||||
def default
|
def default
|
||||||
@default ||= case type
|
@default ||= case type
|
||||||
when :integer then 1
|
when :integer then 1
|
||||||
when :float then 1.5
|
when :float then 1.5
|
||||||
when :decimal then "9.99"
|
when :decimal then "9.99"
|
||||||
when :datetime, :timestamp, :time then Time.now.to_s(:db)
|
when :datetime, :timestamp, :time then Time.now.to_s(:db)
|
||||||
when :date then Date.today.to_s(:db)
|
when :date then Date.today.to_s(:db)
|
||||||
when :string then name == "type" ? "" : "MyString"
|
when :string then name == "type" ? "" : "MyString"
|
||||||
when :text then "MyText"
|
when :text then "MyText"
|
||||||
when :boolean then false
|
when :boolean then false
|
||||||
when :references, :belongs_to, :rich_text then nil
|
when :references, :belongs_to,
|
||||||
|
:attachment, :attachments,
|
||||||
|
:rich_text then nil
|
||||||
else
|
else
|
||||||
""
|
""
|
||||||
end
|
end
|
||||||
|
@ -157,8 +160,16 @@ module Rails
|
||||||
type == :rich_text
|
type == :rich_text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def attachment?
|
||||||
|
type == :attachment
|
||||||
|
end
|
||||||
|
|
||||||
|
def attachments?
|
||||||
|
type == :attachments
|
||||||
|
end
|
||||||
|
|
||||||
def virtual?
|
def virtual?
|
||||||
rich_text?
|
rich_text? || attachment? || attachments?
|
||||||
end
|
end
|
||||||
|
|
||||||
def inject_options
|
def inject_options
|
||||||
|
|
|
@ -187,6 +187,7 @@ module Rails
|
||||||
|
|
||||||
def attributes_names # :doc:
|
def attributes_names # :doc:
|
||||||
@attributes_names ||= attributes.each_with_object([]) do |a, names|
|
@attributes_names ||= attributes.each_with_object([]) do |a, names|
|
||||||
|
next if a.attachments?
|
||||||
names << a.column_name
|
names << a.column_name
|
||||||
names << "password_confirmation" if a.password_digest?
|
names << "password_confirmation" if a.password_digest?
|
||||||
names << "#{a.name}_type" if a.polymorphic?
|
names << "#{a.name}_type" if a.polymorphic?
|
||||||
|
|
|
@ -32,6 +32,14 @@ module Rails
|
||||||
hook_for :helper, as: :scaffold do |invoked|
|
hook_for :helper, as: :scaffold do |invoked|
|
||||||
invoke invoked, [ controller_name ]
|
invoke invoked, [ controller_name ]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def permitted_params
|
||||||
|
params = attributes_names.map { |name| ":#{name}" }.join(", ")
|
||||||
|
params += attributes.select(&:attachments?).map { |a| ", #{a.name}: []" }.join
|
||||||
|
params
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -54,7 +54,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
||||||
<%- if attributes_names.empty? -%>
|
<%- if attributes_names.empty? -%>
|
||||||
params.fetch(:<%= singular_table_name %>, {})
|
params.fetch(:<%= singular_table_name %>, {})
|
||||||
<%- else -%>
|
<%- else -%>
|
||||||
params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
|
params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
|
||||||
<%- end -%>
|
<%- end -%>
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,7 +61,7 @@ class <%= controller_class_name %>Controller < ApplicationController
|
||||||
<%- if attributes_names.empty? -%>
|
<%- if attributes_names.empty? -%>
|
||||||
params.fetch(:<%= singular_table_name %>, {})
|
params.fetch(:<%= singular_table_name %>, {})
|
||||||
<%- else -%>
|
<%- else -%>
|
||||||
params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
|
params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
|
||||||
<%- end -%>
|
<%- end -%>
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,6 +42,12 @@ class GeneratedAttributeTest < Rails::Generators::TestCase
|
||||||
assert_field_type :rich_text, :rich_text_area
|
assert_field_type :rich_text, :rich_text_area
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_field_type_returns_file_field
|
||||||
|
%w(attachment attachments).each do |attribute_type|
|
||||||
|
assert_field_type attribute_type, :file_field
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_field_type_with_unknown_type_returns_text_field
|
def test_field_type_with_unknown_type_returns_text_field
|
||||||
%w(foo bar baz).each do |attribute_type|
|
%w(foo bar baz).each do |attribute_type|
|
||||||
assert_field_type attribute_type, :text_field
|
assert_field_type attribute_type, :text_field
|
||||||
|
@ -88,7 +94,7 @@ class GeneratedAttributeTest < Rails::Generators::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_default_value_is_nil
|
def test_default_value_is_nil
|
||||||
%w(references belongs_to rich_text).each do |attribute_type|
|
%w(references belongs_to rich_text attachment attachments).each do |attribute_type|
|
||||||
assert_field_default_value attribute_type, nil
|
assert_field_default_value attribute_type, nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -368,32 +368,38 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
|
||||||
|
|
||||||
def test_add_migration_ignores_virtual_attributes
|
def test_add_migration_ignores_virtual_attributes
|
||||||
migration = "add_rich_text_content_to_messages"
|
migration = "add_rich_text_content_to_messages"
|
||||||
run_generator [migration, "content:rich_text"]
|
run_generator [migration, "content:rich_text", "video:attachment", "photos:attachments"]
|
||||||
|
|
||||||
assert_migration "db/migrate/#{migration}.rb" do |content|
|
assert_migration "db/migrate/#{migration}.rb" do |content|
|
||||||
assert_method :change, content do |change|
|
assert_method :change, content do |change|
|
||||||
assert_no_match(/add_column :messages, :content, :rich_text/, change)
|
assert_no_match(/add_column :messages, :content, :rich_text/, change)
|
||||||
|
assert_no_match(/add_column :messages, :video, :attachment/, change)
|
||||||
|
assert_no_match(/add_column :messages, :photos, :attachments/, change)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_create_table_migration_ignores_virtual_attributes
|
def test_create_table_migration_ignores_virtual_attributes
|
||||||
run_generator ["create_messages", "content:rich_text"]
|
run_generator ["create_messages", "content:rich_text", "video:attachment", "photos:attachments"]
|
||||||
assert_migration "db/migrate/create_messages.rb" do |content|
|
assert_migration "db/migrate/create_messages.rb" do |content|
|
||||||
assert_method :change, content do |change|
|
assert_method :change, content do |change|
|
||||||
assert_match(/create_table :messages/, change)
|
assert_match(/create_table :messages/, change)
|
||||||
assert_no_match(/ t\.rich_text :content/, change)
|
assert_no_match(/ t\.rich_text :content/, change)
|
||||||
|
assert_no_match(/ t\.attachment :video/, change)
|
||||||
|
assert_no_match(/ t\.attachments :photos/, change)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_remove_migration_with_virtual_attributes
|
def test_remove_migration_with_virtual_attributes
|
||||||
migration = "remove_content_from_messages"
|
migration = "remove_content_from_messages"
|
||||||
run_generator [migration, "content:rich_text"]
|
run_generator [migration, "content:rich_text", "video:attachment", "photos:attachments"]
|
||||||
|
|
||||||
assert_migration "db/migrate/#{migration}.rb" do |content|
|
assert_migration "db/migrate/#{migration}.rb" do |content|
|
||||||
assert_method :change, content do |change|
|
assert_method :change, content do |change|
|
||||||
assert_no_match(/remove_column :messages, :content, :rich_text/, change)
|
assert_no_match(/remove_column :messages, :content, :rich_text/, change)
|
||||||
|
assert_no_match(/remove_column :messages, :video, :attachment/, change)
|
||||||
|
assert_no_match(/remove_column :messages, :photos, :attachments/, change)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -509,8 +509,28 @@ class ModelGeneratorTest < Rails::Generators::TestCase
|
||||||
assert_file "app/models/message.rb", expected_file
|
assert_file "app/models/message.rb", expected_file
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_model_with_attachment_attribute_adds_has_one_attached
|
||||||
|
run_generator ["message", "video:attachment"]
|
||||||
|
expected_file = <<~FILE
|
||||||
|
class Message < ApplicationRecord
|
||||||
|
has_one_attached :video
|
||||||
|
end
|
||||||
|
FILE
|
||||||
|
assert_file "app/models/message.rb", expected_file
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_model_with_attachments_attribute_adds_has_many_attached
|
||||||
|
run_generator ["message", "photos:attachments"]
|
||||||
|
expected_file = <<~FILE
|
||||||
|
class Message < ApplicationRecord
|
||||||
|
has_many_attached :photos
|
||||||
|
end
|
||||||
|
FILE
|
||||||
|
assert_file "app/models/message.rb", expected_file
|
||||||
|
end
|
||||||
|
|
||||||
def test_skip_virtual_fields_in_fixtures
|
def test_skip_virtual_fields_in_fixtures
|
||||||
run_generator ["message", "content:rich_text"]
|
run_generator ["message", "content:rich_text", "video:attachment", "photos:attachments"]
|
||||||
|
|
||||||
assert_generated_fixture("test/fixtures/messages.yml",
|
assert_generated_fixture("test/fixtures/messages.yml",
|
||||||
"one" => nil, "two" => nil)
|
"one" => nil, "two" => nil)
|
||||||
|
|
|
@ -80,6 +80,15 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_controller_permit_attachment_attributes
|
||||||
|
run_generator ["Message", "video:attachment", "photos:attachments"]
|
||||||
|
|
||||||
|
assert_file "app/controllers/messages_controller.rb" do |content|
|
||||||
|
assert_match(/def message_params/, content)
|
||||||
|
assert_match(/params\.require\(:message\)\.permit\(:video, photos: \[\]\)/, content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_helper_are_invoked_with_a_pluralized_name
|
def test_helper_are_invoked_with_a_pluralized_name
|
||||||
run_generator
|
run_generator
|
||||||
assert_file "app/helpers/users_helper.rb", /module UsersHelper/
|
assert_file "app/helpers/users_helper.rb", /module UsersHelper/
|
||||||
|
@ -276,4 +285,13 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
|
||||||
assert_no_match(/assert_redirected_to/, content)
|
assert_no_match(/assert_redirected_to/, content)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_api_only_generates_params_for_attachments
|
||||||
|
run_generator ["Message", "video:attachment", "photos:attachments", "--api"]
|
||||||
|
|
||||||
|
assert_file "app/controllers/messages_controller.rb" do |content|
|
||||||
|
assert_match(/def message_params/, content)
|
||||||
|
assert_match(/params\.require\(:message\)\.permit\(:video, photos: \[\]\)/, content)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -471,6 +471,24 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_scaffold_generator_attachments
|
||||||
|
run_generator ["message", "video:attachment", "photos:attachments", "images:attachments"]
|
||||||
|
|
||||||
|
assert_file "app/models/message.rb", /has_one_attached :video/
|
||||||
|
assert_file "app/models/message.rb", /has_many_attached :photos/
|
||||||
|
|
||||||
|
assert_file "app/controllers/messages_controller.rb" do |content|
|
||||||
|
assert_instance_method :message_params, content do |m|
|
||||||
|
assert_match(/permit\(:video, photos: \[\], images: \[\]\)/, m)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_file "app/views/messages/_form.html.erb" do |content|
|
||||||
|
assert_match(/^\W{4}<%= form\.file_field :video %>/, content)
|
||||||
|
assert_match(/^\W{4}<%= form\.file_field :photos, multiple: true %>/, content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_scaffold_generator_database
|
def test_scaffold_generator_database
|
||||||
with_secondary_database_configuration do
|
with_secondary_database_configuration do
|
||||||
run_generator ["posts", "--database=secondary"]
|
run_generator ["posts", "--database=secondary"]
|
||||||
|
|
Loading…
Reference in a new issue