1
0
Fork 0
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:
Chris Oliver 2019-03-30 11:54:47 -05:00
parent 4e076b03b6
commit ecdcf06cb2
13 changed files with 130 additions and 25 deletions

View file

@ -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 -%>

View file

@ -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 %> %>

View file

@ -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 -%>

View file

@ -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

View file

@ -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?

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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"]