这次做新项目的时候,把图片都放在了一个表里,其他表中不再存图片信息,通过多态关联建立表之间的关系。
(1)新建picture表,component表不需要处理
class CreatePictures < ActiveRecord::Migration[5.0]
def change
create_table :pictures do |t|
t.integer :imageable_id
t.string :imageable_type
t.string :name
t.string :md5
t.string :url
t.timestamps
end
add_index :pictures, [:imageable_type, :imageable_id]
end
end
(2)关于model的关联
多态关联的文档 http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
A slightly more advanced twist on associations is the polymorphic association.
With polymorphic associations, a model can belong to more than one other model, on a single association.
For example, you might have a picture model that belongs to either an employee model or a product model.
Here's how this could be declared:
class Component < ApplicationRecord
serialize :hints, Hash
has_many :pictures, as: :imageable
accepts_nested_attributes_for :pictures, reject_if: proc { |attributes| attributes['md5'].blank? || attributes['url'].blank? }
end
class Picture < ApplicationRecord
belongs_to :imageable, polymorphic: true
end
对下拉框的处理
PICTURE_NAME = {
'海报图' => 'poster',
'背景' => 'background',
'左下角角标' => 'left_bottom_corner',
'右下角角标' => 'right_bottom_corner',
'左上角角标' => 'left_top_corner',
'右上角角标' => 'right_top_corner'
}
def picture_name picture_name
PICTURE_NAME.invert[picture_name]
end
关于多态关联的Instance Public methods http://api.rubyonrails.org/
Defines an attributes writer for the specified association(s).
Supported options:
-
:allow_destroy
-
If true, destroys any members from the attributes hash with a
_destroy
key and a value that evaluates totrue
(eg. 1, '1', true, or 'true'). This option is off by default.
:reject_if
-
Allows you to specify a Proc or a Symbol pointing to a method that checks whether a record should be built for a certain attribute hash. The hash is passed to the supplied Proc or the method and it should return either
true
orfalse
. -
When no
:reject_if
is specified, a record will be built for all attribute hashes that do not have a_destroy
value that evaluates to true. Passing:all_blank
instead of a Proc will create a proc that will reject a record where all the attributes are blank excluding any value for_destroy
.
:limit
-
Allows you to specify the maximum number of associated records that can be processed with the nested attributes.
-
Limit also can be specified as a Proc or a Symbol pointing to a method that should return a number.
-
If the size of the nested attributes array exceeds the specified limit, NestedAttributes::TooManyRecordsexception is raised.
-
If omitted, any number of associations can be processed. Note that the
:limit
option is only applicable to one-to-many associations.
:update_only
-
For a one-to-one association, this option allows you to specify how nested attributes are going to be used when an associated record already exists.
-
In general, an existing record may either be updated with the new set of attribute values or be replaced by a wholly new record containing those values. By default the
:update_only
option isfalse
and the nested attributes are used to update the existing record only if they include the record's:id
value. Otherwise a new record will be instantiated and used to replace the existing one. -
However if the
:update_only
option istrue
, the nested attributes are used to update the record's attributes always, regardless of whether the:id
is present. The option is ignored for collection associations.
Examples:
# creates avatar_attributes=
accepts_nested_attributes_for :avatar, reject_if: proc { |attributes| attributes['name'].blank? }
# creates avatar_attributes=
accepts_nested_attributes_for :avatar, reject_if: :all_blank
# creates avatar_attributes= and posts_attributes=
accepts_nested_attributes_for :avatar, :posts, allow_destroy: true
If the hash contains an id
key that matches an already associated record, the matching record will be modified:
如果在编辑或者新建component的时候,传的picture相关的参数里带有id,那么这条图片记录会被修改,不会被新建。
member.attributes = {
name: 'Joe',
posts_attributes: [
{ id: 1, title: '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!' },
{ id: 2, title: '[UPDATED] other post' }
]
}
member.posts.first.title # => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!'
member.posts.second.title # => '[UPDATED] other post'
(3)controller里的处理
Nested Parameters
http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
private
def set_component
@component = Component.find(params[:id])
end
def component_params
params.require(:component).permit(:release_id, :component_type_id, :name,
:unitary, {pictures_attributes: [:id, :imageable_type, :imageable_id, :name, :url, :md5]},
:remark, component_ids: [], hints: [:left, :mid, :right]
)
end
(4)_form.html.erb里的处理
<div class="image-group">
<% @component.pictures.each do |p| %>
<%= hidden_field_tag 'component[pictures_attributes][][id]', p.id %>
<div class="form-group">
<%= f.label 'name', class: 'col-sm-2 control-label' %>
<div class="col-sm-4">
<%= text_field_tag 'component[pictures_attributes][][name]', @component.picture_name(p.name), class: 'form-control' %>
</div>
</div>
<div class="form-group">
<%= f.label 'md5', class: 'col-sm-2 control-label' %>
<div class="col-sm-4">
<%= text_field_tag 'component[pictures_attributes][][md5]', p.md5, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<%= f.label 'url', class: 'col-sm-2 control-label' %>
<div class="col-sm-4">
<%= image_tag p.url, :width => 300 %><br/>
</div>
<div class="col-sm-4">
<%= text_field_tag 'component[pictures_attributes][][url]', p.url, class: 'form-control' %>
</div>
</div>
<% end %>
</div>
<div class="image-group image-create-group">
<div class="form-group">
<%= f.label 'name', class: 'col-sm-2 control-label' %>
<div class="col-sm-4">
<%= select_tag 'component[pictures_attributes][][name]', options_for_select(Component::PICTURE_NAME,""),
class: "form-control" %>
</div>
</div>
<div class="form-group">
<%= f.label 'md5', class: 'col-sm-2 control-label' %>
<div class="col-sm-4">
<%= text_field_tag 'component[pictures_attributes][][md5]', nil, class: 'form-control' %>
</div>
</div>
<div class="form-group">
<%= f.label 'url', class: 'col-sm-2 control-label' %>
<div class="col-sm-4">
<%= text_field_tag 'component[pictures_attributes][][url]', nil, class: 'form-control' %>
</div>
</div>
</div>