Rails 4 Полиморфная загрузка изображений с помощью Paperclip не работает для всех моделей
Rails новичок здесь... и ТАК первоклассный....
После пары уроков я решил попробовать создать систему управления событиями. Ничего подобного амбициям, верно? События, художники и компании должны иметь возможность загрузить одно изображение с помощью скрепки и вложенных форм. Я создал полиморфный класс Picture, и он отлично подходит для загрузки / редактирования изображения для Artist, но когда я пытаюсь настроить его для Event, используя точно такой же код, я получаю ошибку "Unpermitted параметр: picture_attributes"... и ничто не спасает в БД.
Я искал / читал ответы в течение последних 3 дней, и я полностью застрял, поэтому я подумал, что выложу свой код сюда и посмотрю, сможет ли кто-нибудь определить, что мне не хватает, и помочь мне понять, как получить это на работу.
Вот фактический код ошибки из моей последней попытки загрузить изображение на событие:
Started PATCH "/events/12" for 127.0.0.1 at 2014-12-19 11:00:37 -0800
Processing by EventsController#update as HTML
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"AVkztH4s+t2oq/vjXloZeWxOW3pyD8sEorE3crMZr4Q=",
"event"=>{"title"=>"Image Upload Test", "description"=>"Will this save to the db?",
"picture_attributes"=>{
"image"=>#<ActionDispatch::Http::UploadedFile:0x007fe7e9f6a3c8 @tempfile=#<Tempfile:/var/folders/kg/_bhw0x954nq1vdxsr4bwktvc0000gn/T/RackMultipart20141219-868-c377uk>,
@original_filename="RED_Tails_1.jpg",
@content_type="image/jpeg",
@headers="Content-Disposition: form-data;
name=\"event[picture_attributes][image]\";
filename=\"RED_Tails_1.jpg\"\r\nContent-Type: image/jpeg\r\n">},
"company_id"=>"1",
"venue_id"=>"1",
"production_artists_attributes"=>{
"0"=>{"artist_id"=>"1",
"role"=>"German Commander",
"_destroy"=>"false",
"artist_type_id"=>"1", "id"=>"20"}}}, "button"=>"", "id"=>"12"}
Event Load (0.2ms) SELECT "events".* FROM "events" WHERE "events"."id" = $1 LIMIT 1 [["id", 12]]
Unpermitted parameters: picture_attributes
(0.2ms) BEGIN
ProductionArtist Load (0.2ms) SELECT "production_artists".* FROM "production_artists" WHERE
"production_artists"."event_id" = $1 AND "production_artists"."id" IN (20) [["event_id", 12]]
SQL (1.3ms) UPDATE "events" SET "company_id" = $1, "description" = $2, "title" = $3, "updated_at" = $4, "venue_id" = $5 WHERE "events"."id" = 12 [["company_id", 1], ["description", "Will this save to the db?"], ["title", "Image Upload Test"], ["updated_at", "2014-12-19 19:00:37.057793"], ["venue_id", 1]]
SQL (1.3ms) UPDATE "production_artists" SET "artist_id" = $1, "role" = $2, "updated_at" = $3 WHERE "production_artists"."id" = 20 [["artist_id", 1], ["role", "German Commander"], ["updated_at", "2014-12-19 19:00:37.065119"]]
(90.1ms) COMMIT
Redirected to http://localhost:3000/events/12
Completed 302 Found in 114ms (ActiveRecord: 93.3ms)
Вот мои модели:
class Event < ActiveRecord::Base
has_one :picture, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :picture
end
class Artist < ActiveRecord::Base
has_one :picture, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :picture
end
class Picture < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
has_attached_file :image, :styles => { :small => "180x180#", :thumb => "60x60#" },
path: ":rails_root/public/system/:attachment/:id/:style/:filename",
url: "/system/:attachment/:id/:style/:filename"
validates_attachment :image, :presence => true,
:content_type => { :content_type => %w(image/jpeg image/jpg image/png) },
:size => { :in => 0..1.megabytes }
end
Вот мои контроллеры:
class ArtistsController < ApplicationController
before_action :set_artist, only: [:show, :edit, :update, :destroy]
def index
@artists = Artist.all
end
def show
end
def new
@artist = Artist.new
@artist.build_picture
end
def edit
end
def create
@artist = Artist.new(artist_params)
respond_to do |format|
if @artist.save
format.html { redirect_to @artist, notice: 'Artist was successfully created.' }
format.json { render :show, status: :created, location: @artist }
else
format.html { render :new }
format.json { render json: @artist.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @artist.update(artist_params)
format.html { redirect_to @artist, notice: 'Artist was successfully updated.' }
format.json { render :show, status: :ok, location: @artist }
else
format.html { render :edit }
format.json { render json: @artist.errors, status: :unprocessable_entity }
end
end
end
private
def set_artist
@artist = Artist.find(params[:id])
end
def artist_params
params.require(:artist).permit(:first_name, :last_name,
picture_attributes: [:image])
end
end
class EventsController < ApplicationController
before_action :set_event, only: [:show, :edit, :update, :destroy]
def index
@events = Event.all
end
def show
end
def new
@event = Event.new
@event.build_venue
@venue = @event.build_venue
@event.build_picture
end
def edit
end
def create
@event = Event.new(event_params)
respond_to do |format|
if @event.save
format.html { redirect_to @event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: @event }
else
format.html { render :new }
format.json { render json: @event.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @event.update(event_params)
format.html { redirect_to @event, notice: 'Event was successfully updated.' }
format.json { render :show, status: :ok, location: @event }
else
format.html { render :edit }
format.json { render json: @event.errors, status: :unprocessable_entity }
end
end
end
def destroy
@event.destroy
respond_to do |format|
format.html { redirect_to events_url, notice: 'Event was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_event
@event = Event.find(params[:id])
end
def event_params
params.require(:event).permit(:title, :description, :image_url, :company_id, :venue_id,
production_artists_attributes: [ :id, :event_id, :artist_id, :artist_type_id, :role, :_destroy,
venues_attributes: [ :id, :name,
picture_attributes: [:image]]] )
end
end
Вот мои взгляды:
The Events form:
<%= form_for @event, html: { multipart: true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<fieldset id="event-meta">
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, rows: 8, class: "form-control" %>
<br />
</div>
</fieldset>
<div class="form-group">
<p>Upload Picture</p>
<%= f.fields_for :picture do |image_upload| %>
<%= image_upload.file_field :image, class: "form-control" %>
<% end %>
</div>
....
The Artist form:
<%= form_for @artist, html: { multipart: true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="form-group">
<%= f.label :first_name %>
<%= f.text_field :first_name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :last_name %>
<%= f.text_field :last_name, class: "form-control" %>
</div>
<div class="form-group">
<p>Upload Picture</p>
<%= f.fields_for :picture do |image_upload| %>
<%= image_upload.file_field :image, class: "form-control" %>
<% end %>
</div>
Так что... мне кажется, все должно работать... но это не так. Я, вероятно, упускаю что-то простое и надеюсь, что кто-то там может указать мне на это.
FWIW... Прошлой ночью во время поиска ответов у меня возникла мысль, что может быть лучше создать полиморфную модель Profile и прикрепить все изображения к тем, у которых есть отношение has_one, но даже если это так... Мне бы очень хотелось, чтобы некоторые помогите понять, почему я не могу заставить это работать сейчас, чтобы я мог узнать, что ожидать в будущем. Я полностью сбит с толку.
2 ответа
После нескольких недель стучать головой о стену... я решил это... но я чувствую себя идиотом. Я оставляю это здесь для любого, кто сталкивается с этой проблемой.
Оказывается, я не совсем понял синтаксис для размещения сильных параметров. Закрывая вложенные атрибуты для художников-постановщиков и площадок перед фотографиями, я смог заставить его работать. Я также получил это работает для модели компании.
Итак, я изменил это:
def event_params
params.require(:event).permit(:title, :description, :image_url, :company_id, :venue_id,
production_artists_attributes: [ :id, :event_id, :artist_id, :artist_type_id, :role, :_destroy,
venues_attributes: [ :id, :name,
picture_attributes: [:image]]] )
end
к этому:
def event_params
params.require(:event).permit(:title, :description, :image_url, :company_id, :venue_id,
production_artists_attributes: [:id, :event_id, :artist_id, :artist_type_id, :role, :_destroy],
venues_attributes: [:id, :name],
picture_attributes: [:image])
end
и все работало как шарм.
Попробуйте обновить event_params
метод к этому:
def event_params
params.require(:event).permit(:title, :description, :image_url, :company_id, :venue_id,
production_artists_attributes: [ :id, :event_id, :artist_id, :artist_type_id, :role, :_destroy,
venues_attributes: [ :id, :name,
imageable_attributes: [:image]]] )
end
Дело в том, что вы устанавливаете as
вариант для has_one
отношение к imageable
и, вероятно, вам придется сделать что-то подобное для представления в полях модели и на модели:
accepts_nested_attributes_for :imageable
<%= f.fields_for :imageable do |image_upload| %>
<%= image_upload.file_field :image, class: "form-control" %>
<% end %>
Дайте мне знать, как это происходит.