I have a model with a Logo as attachment.
When user uploads an image, the validation name and url validation should be skipped.
The validates :logo should be still validated
Is this possible, and if yes: How?
Thank you!
class MyModel < ApplicationRecord
belongs_to :user
has_one_attached :logo do |attachable|
attachable.variant :thumbnail, resize_to_fit: [100, 100]
end
validates :logo, content_type: %w[image/png image/jpg image/jpeg]
# following line should be skipped
validates_presence_of :name, :url # this should be skipped when attaching an image !!!
end
# MyModelController
# That is my current controller action
# PATCH /shops/update_logo
def update_logo
if logo_params[:logo].present?
logo = logo_params[:logo]
if logo && #current_user.my_model.logo.attach(logo)
render json: #current_user, status: :ok
else
render json: #current_user.my_model.errors, status: :unprocessable_entity, error: #current_user.my_model.errors.full_messages.join(', ')
end
else
render json: { error: "no image selected" }, status: :unprocessable_entity
end
end
Some hack with :on
class MyModel < ApplicationRecord
validates :name, :url, presence: true, on: :not_attachment
validates :logo, content_type: %w[image/png image/jpg image/jpeg]
end
my_model.name = my_model.url = nil
my_model.logo.attach(logo)
my_model.valid? # => true
my_model.name = my_model.url = nil
my_model.save(context: :not_attachment)
my_model.valid? # => false
Related
I have multiple methods within my controller that takes in query parameters. How can I validate that I am being passed in valid parameters? For example, for the index method, how can I make sure that I am getting an array of authorIds.
def index
author_ids_array = params[:authorIds].to_s.split(',')
posts = Post
.get_posts_by_user_id(author_ids_array)
.order(sort_column => sort_direction)
if posts
render json: { posts: posts }, status: :ok
else
render json: {error: posts.errors}, status: :unprocessable_entity
end
end
Or in this update method. How can I validate that I am getting a valid postId
def update
post = current_user.posts.find_by(id: params[:id])
if post.update!(post_params)
post_hash = post.as_json
post_hash.merge!(authorIds: params[:authorIds])
render json: {post: post_hash}, status: :ok
else
render json: {error: post.errors}, status: :unprocessable_entity
end
end
Update:
Post Model:
class Post < ApplicationRecord
# Associations
has_many :user_posts
has_many :users, through: :user_posts, dependent: :destroy
# Validations
validates :text, presence: true, length: { minimum: 3 }
validates :popularity, inclusion: { in: 0.0..1.0 }
def tags
if super
super.split(",")
end
end
def tags=(value)
if value.kind_of? Array
super value.join(",")
else
super value
end
end
def self.get_posts_by_user_id(user_id)
Post.joins(:user_posts).where(user_posts: { user_id: user_id })
end
end
User Model:
class User < ApplicationRecord
has_secure_password
# Associations
has_many :user_posts
has_many :posts, through: :user_posts, dependent: :destroy
# Validations
validates :username, :password, presence: true
validates :password, length: { minimum: 6 }
validates :username, uniqueness: true
end
User_post Model:
class UserPost < ApplicationRecord
belongs_to :user
belongs_to :post
end
You can use specific render like below user this in any method like
def index
return render body: params.inspect
.
.
end
user below code
return render body: params.inspect
so when you use index it will give you params which is passing
OR you can user below code in your application.html.erb above <%= yield%>
<%= debug(params) if Rails.env.development? %>
After your clarifications, your question remains unclear to me and it is difficult to guess what you're doing. But I understood that you want to ensure that params[:authorIds] or anything else is an array.
You can see if a given variable is an array the following way:
a = ["1","2"]
if a.is_a?(Array)
puts "is an array"
end
With params: params[:authorIds].is_a?(Array)
You can use byebug (before Rails 7) or debugger (for Rails 7) to inspect what a param is. As an example:
(ruby#whatever: cluster worker 1: 42779 [MyApp]#42793) params[:ids].class
Array
Basically in my form i am uploading a pic and has the option to delete the picture when a picture already exists. But i would like to delete the image from my disk after a new picture was uploaded. How to do that in ActiveAdmin
Admin model:
f.inputs do
f.input :image, as: :file, hint: (f.object.image.attached?) ? image_tag(url_for(f.object.image)) : content_tag(:span, "JPG oder PNG")
if f.object.image.present?
f.input :remove_image, as: :boolean, required: false, label: "Remove"
end
end
f.actions
Model:
belongs_to :parent
default_scope { order(:position) }
has_one_attached :image, :dependent => :destroy
attr_writer :remove_image
validates :image, blob: { content_type: ['image/png', 'image/jpg', 'image/jpeg'] }
before_validation :image_delete
def remove_image
#remove_image || false
end
def image_delete
self.image.purge if self.remove_image == '1'
end
Well i am posting my answer in case it helps someone in future. It's pretty easy but a bit tricky. I had to adjust my model a bit.
Removed before_validation
Model:
belongs_to :parent
default_scope { order(:position) }
has_one_attached :image, :dependent => :destroy
attr_writer :remove_image
validates :image, blob: { content_type: ['image/png', 'image/jpg', 'image/jpeg'] }
def remove_image
#remove_image || false
end
In admin model inside controller the method update gets called on form submission. Simply deleting the initial image and saving the new one from params
def update
v = Model.find( params[:id] )
if params[:model][:image].present?
v.image.purge
v.image = params[:model][:image]
end
if params[:model][:remove_image].present? && params[:model][:remove_image] == '1'
v.image.purge
end
if v.save
redirect_to model_path(v)
else
render :edit
end
end
since i also delete image individually remove_image was used.
More source: https://spin.atomicobject.com/2016/01/29/uploading-files-active-admin/
I am brand new here. I have been fighting with a rails app for hours now and need an answer. I have searched and tried many suggestions related to what I am trying to accomplish, but to no avail. I got the paperclip gem running for my rails app yesterday, and it was a breeze to add an attachment to a single model. However, I defined an agnostic, polymorphic attachments table to hold attached files for all models that need this functionality.
My issue is that I cannot get the attached file to save through nested parameters. All my parameters are accepted, but the db rolls back and doesn't save (using guard). Message is: 'attachments.attachable_id'=>'can't be blank'. I need this to be the foreign key of the related table, and this has to be saved along with the attachment_type. Here's what I have:
class ReportsController < ApplicationController
def new
#report = Report.new
#report.attachments.build(attachable_id: #report.id)
end
def create
#report = Report.new(params)
#report.attachments.build
respond_to do |format|
if #report.save
format.html { redirect_to #report, notice: 'Report was successfully created.' }
format.json { render json: #report, status: :created, location: #report }
else
format.html { render action: "new" }
format.json { render json: #report.errors, status: :unprocessable_entity }
end
end
end
private
def report_params
params.require(:report).permit(:filing_year, :filing_number, :order_number, :location, :environmental_review,:biological_review, :cultural_review, :date_received, :status, attachments_attributes: [:id, :attachable_id, :attachable_type, :attachment])
end
end
And for the models:
class Attachment < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
validates :attachable_id, :attachable_type, presence: true
do_not_validate_attachment_file_type :attachment
Paperclip.interpolates :attached_to do |attachment, style|
attachment.instance.attachable.class.to_s.downcase
end
has_attached_file :attachment,
:url => "/attachments/:id/:basename.:extension",
:path => ":rails_root/public/attachments/:attached_to/:id/:basename.:extension",
:default_url => "/attachments/original/no-file.txt"
end
class Report < ActiveRecord::Base
has_one :environmental_review
has_many :attachments, as: :attachable
accepts_nested_attributes_for :attachments
validates :order_number, presence: true
.
.
.
end
And view (in slim):
.report
= form_for #report do |f|
.
.
.
= f.fields_for :attachments do |a|
= a.file_field :attachment
.
.
.
Thank you.
Well for one in your create method you call #reports.attachments.build again, but don't set the assignable_id, you need to do that. The other thing you can do is add a hidden form field that has the name attachable_id.
I installed it by following the manual on paperclip github page and I get the given error. What am I doing wrong?
I have 4 input fields: title (text_field), description (text_area), price (text_field) and image (file_field). Why am I even getting this error with the prefix title in it? What has the title field got to do with it, are there any conflicts maybe? I did create and run the migrations so this is realy kind of weird I think.
Any help appreciated. Thanks.
EDIT:
The migration is as follows:
class AddImageColumnsToProducts < ActiveRecord::Migration
def change
add_attachment :products, :image
end
end
It results like so:
image_file_name varchar(255)
image_content_type varchar(255)
image_file_size int(11)
image_updated_at datetime
Model:
class Product < ActiveRecord::Base
has_attached_file :image, :styles => { :medium => "600x600>", :thumb => "258x258>" },
:default_url => "images/:style/:slug.png"
validates :title, :content, :image, :attachment_presence => true
validates_with AttachmentPresenceValidator, :attributes => :image
end
Controller:
def create
#product = Product.new(product_params)
#product.image = params[:product][:image]
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render action: 'show', status: :created, location: #product }
else
format.html { render action: 'new' }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
The issue is with your validation. The line which says
validates :title, :content, :image, :attachment_presence => true
assumes title, content & image as 3 image-based attributes. But, I understand that only 'image' is the image-based field. So, your code should rather be:
validates :title, :content, :presence=>true
validates :image, :attachment_presence => true
Also, I don't see the 'content' field in the request-log. I guess, you mean 'description'. Make sure you have the same attribute-names in the model-validations, database-schema & view files.
I've been working on this all night and it makes no sense. I'm adapting an old photo web app to have albums in it. I made "fails" (basically images) a nested resource of albums. I am using carrierwave to upload files to an S3 bucket.
the weird thing is: the upload works perfectly fine for the album model (album image), but it doesn't upload for the fail model.
I don't see why it'd be a problem that it's a nested resource now. It's not a problem displaying it's that for some reason, it goes through the form fine, passes validations fine, no errors are thrown, it redirects to fails#index like it was successful, but there is nothing in the db or in S3.
Code is below. All code at https://github.com/spq24/failboard
Fail Model
class Fail < ActiveRecord::Base
attr_accessible :description, :image, :remote_image_url, :fail_title, :tag_list, :processed, :youtube_url, :album_id
make_voteable
acts_as_taggable
belongs_to :album
mount_uploader :image, ImageUploader
validates :description, length: { :maximum => 200 }
validates :album_id, presence: true
validates :image, presence: true
validates :fail_title, presence: true, length: { :maximum => 50 }
validate :maximum_amount_of_tags
def maximum_amount_of_tags
number_of_tags = tag_list_cache_on("tags").uniq.length
errors.add(:base, "Please only add up to 5 tags") if number_of_tags > 5
end
before_save :update_attachment_attributes
def update_attachment_attributes
if image.present? && image_changed?
self.content_type = image.file.content_type
self.file_size = image.file.size
end
end
def next
user.fails.where("id > ?", id).order("id ASC").first
end
def prev
user.fails.where("id < ?", id).order("id DESC").first
end
end
Album Model
class Album < ActiveRecord::Base
attr_accessible :name, :image, :image_url, :created_at
belongs_to :user
has_many :fails, dependent: :destroy
mount_uploader :image, ImageUploader
validates :user_id, presence: true
validates :image, presence: true
validates :name, presence: true, length: { :maximum => 50 }
before_save :update_attachment_attributes
def update_attachment_attributes
if image.present? && image_changed?
#self.content_type = image.file.content_type
#self.file_size = image.file.size
end
end
def next
user.fails.where("id > ?", id).order("id ASC").first
end
def prev
user.fails.where("id < ?", id).order("id DESC").first
end
end
Fails Controller
def new
#fail = Fail.new(:album_id => params[:album_id])
respond_to do |format|
format.html # new.html.erb
format.json { render json: #fail }
end
end
def create
#fail = Fail.new(params[:fail])
respond_to do |format|
if #fail.save
format.html { redirect_to #fail.album, notice: 'You added a new photo!' }
format.json { render json: #fail, status: :created, location: #fail }
else
format.html { render action: "new" }
format.json { render json: #fail.errors, status: :unprocessable_entity }
end
end
end
routes.rb
resources :albums do
get 'tags/:tag', to: 'fails#index', as: :tag
resources :fails do
member do
post :up_vote
end
end
Debug Hash (this turns red when I try to upload, but I don't see anything that would cause the error)
Here is the debug info:
{"utf8"=>"✓", "authenticity_token"=>"Hz6Gl95ultYDNIEjQioIckB8JXQwhiMxXIM9jrfqd5Q=", "fail"=>{"fail_title"=>"tester", "image"=>#<ActionDispatch::Http::UploadedFile:0x56195e8 #original_filename="pic19.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"fail[image]\"; filename=\"pic19.jpg\"\r\nContent-Type: image/jpeg\r\n", #tempfile=#<File:C:/Users/Kinertia/AppData/Local/Temp/RackMultipart20131125-10428-m2ktp2>>, "description"=>"", "tag_list"=>"test"}, "commit"=>"Create Fail", "controller"=>"fails", "action"=>"index"}
If there is anything else needed please let me know and I will put it here. Thank you for all the help!
Have you tried validating the integrity or processing of the fail image?
validates_integrity_of :avatar
validates_processing_of :avatar
validates_download_of :avatar
By default it fails silently, which kinda sucks.
I also recommend trying to create the record in the rails console, which can help to isolate the problem to either the model or view/controller layers. In your case this would look something like:
Fail.create!(
image: File.open('path/to/known/file.jpg'),
album_id: 1,
fail_title: 'Title'
)