问题
I'm using the shrine gem in form object, I want to clip images, so, I followed https://github.com/shrinerb/shrine/wiki/Image-Cropping, but, happed above error, I think that it seems to be don't recognize photos models
views
<%= form_with model: @blog_form , url: user_blogs_path ,local: true do |f| %>
<div class="field">
<% f.label :title %>
<%= f.text_field :title %>
</div>
<div class="field">
<% f.label :content %>
<%= f.text_area :content %>
</div>
<div class="field">
<% f.label :user_id %>
<%= f.hidden_field :user_id, value: current_user.id %>
</div>
<div class ="field">
<%= f.fields_for :photos, @blog_form do |photos_fileds| %>
<%= photos_fileds.label :image %>
<%= photos_fileds.hidden_field :image, value: photos_fileds.cached_image_data if defined?
(photos_filed.cached_image_data) %>
%= photos_fileds.file_field :image %><br/>
<div>
<img id="image" src="<%= photos_fileds.image_url %>"
</div>
<% end %>
</div>
image_uploader
require "vips"
require "image_processing/vips"
class ImageUploader < Shrine
plugin :derivatives
THUMBNAILS = {
large: [800, 800],
medium: [600, 600],
small: [300, 300],
}
Attacher.derivatives do |original|
vips = ImageProcessing::Vips.source(original)
vips = vips.crop(*file.crop_points) # apply cropping
THUMBNAILS.transform_values do |(width, height)|
vips.resize_to_limit!(width, height)
end
end
plugin :derivation_endpoint, prefix: "derivations/image"
# Default URLs of missing derivatives to on-the-fly processing.
Attacher.default_url do |derivative: nil, **|
next unless derivative && file
file.derivation_url :transform, shrine_class.urlsafe_serialize(
crop: file.crop_points,
resize_to_limit: THUMBNAILS.fetch(derivative),
)
end
# Generic derivation that applies a given sequence of transformations.
derivation :transform do |file, transformations|
transformations = shrine_class.urlsafe_deserialize(transformations)
vips = ImageProcessing::Vips.source(file)
vips.apply!(transformations)
end
end
class UploadedFile
# convenience method for fetching crop points from metadata
def crop_points
metadata.fetch("crop").fetch_values("x", "y", "width", "height")
end
end
shrine.rb
require "shrine"
require "shrine/storage/file_system"
Shrine.storages = {
cache: Shrine::Storage::FileSystem.new("app/assets/images", prefix: "uploads/cache"), # temporary
store: Shrine::Storage::FileSystem.new("app/assets/images", prefix: "uploads"), # permanent
}
Shrine.plugin :activerecord # loads Active Record integration
Shrine.plugin :cached_attachment_data # enables retaining cached file across form redisplays
Shrine.plugin :restore_cached_data # extracts metadata for assigned cached files
Shrine.plugin :determine_mime_type
Shrine.plugin :derivatives
Shrine.plugin :backgrounding
Shrine::Attacher.promote_block { PromoteJob.perform_later(record, name, file_data) }
Shrine::Attacher.destroy_block { DestroyJob.perform_later(data) }
Shrine.plugin :derivation_endpoint, secret_key: Rails.application.secret_key_base
Shrine.plugin :default_url
cropbox.js
import 'cropperjs/dist/cropper.css'
import Cropper from 'cropperjs'
function cropbox(image, url, { onCrop }) {
image.src = url
new Cropper(image, {
aspectRatio: 1,
viewMode: 1,
guides: false,
autoCropArea: 1.0,
background: false,
zoomable: false,
crop: event => onCrop(event.detail)
})
}
export default cropbox
fileUpload.js
import cropbox from 'cropbox'
// ...
uppy.on('upload-success', (file, response) => {
// retrieve uploaded file data
const uploadedFileData = response.body['data']
// set hidden field value to the uploaded file data so that it's submitted
// with the form as the attachment
hiddenInput.value = JSON.stringify(uploadedFileData)
cropbox(imagePreview, response.uploadURL, {
onCrop(detail) {
let fileData = JSON.parse(hiddenInput.value)
fileData['metadata']['crop'] = detail
hiddenInput.value = JSON.stringify(fileData)
}
})
})
promote_job.rb
class PromoteJob < ApplicationJob
def perform(record, name, file_data)
attacher = Shrine::Attacher.retrieve(model: record, name: name, file: file_data)
attacher.create_derivatives
attacher.atomic_promote
end
end
destroy_job.rb
class DestroyJob < ApplicationJob
def perform(data)
attacher = Shrine::Attacher.from_data(data)
attacher.destroy
end
end
route.rb
Rails.application.routes.draw do
mount ImageUploader.derivation_endpoint => "/derivations/image"
get 'sessions/new'
devise_for :users
resources :users do
resources :blogs
end
# For details on the DSL available within this file, see
https://guides.rubyonrails.org/routing.html
end
blog_form.rb
class BlogForm
include ActiveModel::Model
attr_accessor :title, :content, :user_id , :photos, :tag_list
def blog_builder
@user = User.find(user_id)
@blogs = @user.blogs.create(title: title , content: content )
end
concerning :PhotosBuilder do
attr_reader :photos_attributes
def photos
@photos ||= Photo.new
end
def photos_attributes=(attributes)
debugger
@photos ||= Photo.new(attributes)
end
end
def build_association
@blogs.photos << @photos if photos?
@user.photos << @photos if photos
end
def save
return false if invalid?
blog_builder
@blogs.save
@photos.save if @photos != nil
build_association
end
def photos?
return true if @photos != nil
end
end
controller
def new
@user = params[:user_id]
@blog_form = BlogForm.new
end
def create
debugger
@blog_form = BlogForm.new(add_params) if has_a_tags? == true
@blog_form = BlogForm.new(blog_form_params)
if @blog_form.save
redirect_to user_blogs_path
else
#False action
end
end
I appreciate you, janko-m, arieljuod I rewrite views, then happened new error
before
ActionView::Template::Error (undefined method `image_url' for #
<ActionView::Helpers::FormBuilder:0x00007f9228150380>):
<%= photos_fileds.hidden_field :image, value: photos.cached_image_data if
defined?(photos.cached_image_data) %>
<%= photos_fileds.file_field :image %><br/>
<div>
<img id="image" src="<%= photos_fileds.image_url %>"
</div>
<% end %>
after
ActionView::Template::Error (undefined method `image_url' for #
<BlogForm:0x00007f9228090a58>):
<%= photos_fileds.hidden_field :image, value:
photos_fileds.cached_image_data if defined?
(photos_filed.cached_image_data) %>
<%= photos_fileds.file_field :image %><br/>
<div>
<img id="image" src="<%= photos_fileds.object.image_url %>" />
</div>
<% end %>
environment rails 6.0.2 ruby 2.5.3
回答1:
This line is trying to call #image_url
on the form object:
<img id="image" src="<%= photos_fileds.image_url %>" />
Instead it needs to be calling #image_url
on the ActiveRecord model:
<img id="image" src="<%= photos_fileds.object.image_url %>" />
来源:https://stackoverflow.com/questions/61523727/actionviewtemplateerror-undefined-method-image-url-for-actionviewhelp