How to reassign uploaded files to some other models rails 3.1 - ruby-on-rails-3

I have a scenario where i am uploading files dynamically using ajax remotipart, then later i assign those uploaded files to any model. I have such settings in uploader.
class DocumentUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.pluralize.underscore}/#{model.documentable_type.to_s.pluralize.underscore}/#{model.documentable_id}"
end
def extension_white_list
%w(doc pdf docx xls xlsx)
end
end
class Document < ActiveRecord::Base
mount_uploader :document, DocumentUploader
belongs_to :documentable, :polymorphic => true
validates :document, :presence => true
validates :description, :presence => true
end
class Post < ActiveRecord::Base
has_many :documents, :as=>:documentable
end
When i upload a document without providing documentable source, it uploads the files to /uploads/documents/uploaded_file.doc
But when i assign that document to some other model like
#post = Post.first
#post.documents << Document.last
#post.save
It save the record correctly and when get url of the file like #post.documents.first.document.url it gave url like this /uploads/documents/posts/10212/uploaded_file.doc where the file was not available.
How can i handle such assignment of pre-existing uploads?

I came here while googling and thought some people might help this piece of code I'm using in a controller to re-assign a file (here it's an image) to another model which is handled with CarrierWave:
def create
temporary_image = TemporaryImage.find(params[:temporary_image][:id])
#player = Player.new(params[:player])
#player.image = File.open(temporary_image.image.current_path)
# now you can handle #player.image as if it was
# originally assigned by CarrierWave
end
where
class Player < ActiveRecord::Base
attr_accessible :image
mount_uploader :image, PlayerImageUploader
end
and
class TemporaryImage < ActiveRecord::Base
attr_accessible :image
mount_uploader :image, TemporaryImageUploader
end
I'm using this in conjunction with an ajax fileupload (stored via TemporaryImage) where the image is immediately presented and can then be cropped. After cropping it is stored within Player.

I solved the issue by doing lot of hit and trail. but finally solved.
class Document < ActiveRecord::Base
mount_uploader :document, DocumentUploader
belongs_to :documentable, :polymorphic => true
validates :document, :presence => true
validates :description, :presence => true
after_update :relocate_files
def relocate_files
src_file = Rails.root.join("public", "uploads", "documents", document.url.split("/").last)
dst_file = Rails.root.join("public", "uploads", "documents", documentable_type.pluralize.underscore, documentable_id.to_s, document.url.split("/").last)
unless FileTest.exists?(dst_file)
FileUtils.mkdir_p(File.dirname(dst_file))
FileUtils.mv(src_file, dst_file)
end
end
end

Related

Can't mass-assign protected attributes with has_many association and create

This is EXTREMELY bizarre. I'm upgrading a Rails 2.3.12 app and running into this same problem over and over again. I'm stumped and nothing else out there seems to touch on it.
I have two models:
class User < ActiveRecord::Base
has_many :logs, :class_name => 'UserLog'
end
and
class UserLog < ActiveRecord::Base
attr_accessor :site_id, :controller, :action, :url, :session
belongs_to :user
validates_presence_of :user
end
then in another controller I'm doing this:
def log_user_activity
#current_user.logs.create(:site_id => #site.id, :controller => params[:controller],
:action => params[:action], :url => request.path,
:session => request.session_options[:id]) if #current_user
end
as you can see, it's pretty straightforward but when I call log_user_activity I'm getting this:
Can't mass-assign protected attributes: site_id, controller, action, url, session
HOWEVER, if I change all my creates or builds to this:
def log_user_activity
log = #current_user.logs.new
log.site_id = #site.id
log.controller = params[:controller]
log.action = params[:action]
log.url = request.path
log.session = request.session_options[:id]
log.save
end
then it works fine!?
Has anyone seen this? Any clues?
In class UserLog, add the following:
attr_accessible :site_id, :controller, :action, :url, :session
The reason you have to use attr_accessible is most likely because you are utilizing a plugin that is relying on this being present for a model. It has happened to all of us and is a royal pita)
Once attr_accessible is designated for a class, then any attribute that is not specified as 'accessible' will not be allowed to be updated.

Options for validates_with

I'm not able to access the values, passed as option in 'validates_with'
My model:
class Person < ActiveRecord::Base
include ActiveModel::Validations
attr_accessible :name, :uid
validates :name, :presence => "true"
validates :uid, :presence => "true"
validates_with IdValidator, :attr => :uid
My Custom Validator:
Class IdValidator < ActiveModel::Validator
def validate(record)
puts options[:attr]
...
...
end
end
For testing purpose, I'm printing "options[:attr]" and all I see is ":uid" in the terminal and not the value in it. Please help!
When you pass in :attr => :uid, you're just passing in a symbol. There's no magic happening hereā€”it just takes the hash of options you've attached and delivers it as the options hash. So when you write it, you see the symbol you've passed.
What you probably want is
Class IdValidator < ActiveModel::Validator
def validate(record)
puts record.uid
...
...
end
end
Because validates_with is a class method, you can't get the values of an individual record in the options hash. If you are interested in a more DRY version, you could try something like:
class IdValidator < ActiveModel::Validator
def validate(record)
puts record[options[:field]]
end
end
class Person < ActiveRecord::Base
include ActiveModel::Validations
attr_accessible :name, :uid
validates :name, :presence => "true"
validates :uid, :presence => "true"
validates_with IdValidator, :field => :uid
end
Where you pass in the name of the field you want evaluated.

Can't mass-assign protected attributes for nested form using cocoon and simple_forms in Rails 3 App

The Problem:
I am getting an error message when submitting my form that says:
ActiveModel::MassAssignmentSecurity::Error in AdmissionRecordsController#create
Can't mass-assign protected attributes: admission_record
My Setup:
I am using Rails 3.2.3, with extra gems including Cocoon 1.0.14 and Simple_Form 2.0.2
The View:
My app/views/admission_records/_form.html.haml looks like:
= simple_form_for [#admission, #record] do |f|
= f.simple_fields_for :vital_signs, #record.vital_signs.build do |vs|
= render :partial => "vital_sign_fields", :locals => { :f => vs }
= link_to_add_association "Add Vital Signs", f, :vital_signs
= f.submit
And my app/views/admission_records/_vital_sign_fields.html.haml looks like:
.nested-fields
= f.label :sbp
= f.text_field :sbp
...
= link_to_remove_association "Remove Vital Sign"
What I am basically trying to do is that I have a resource called AdmissionRecord nested within another resource called PatientAdmission (route.rb shown below). I have another resource called VitalSign which I want to be able to create via a nested form (using cocoon and simple_form) when creating the AdmissionRecord
My config/routes.rb file looks like:
resources :patient_admissions do
resources :admission_records
end
The Models:
My app/models/patient_admission.rb looks like:
class PatientAdmission < ActiveRecord::Base
has_many :admission_records, :dependent => :destroy
end
My app/models/admission_record.rb looks like:
class AdmissionRecord < ActiveRecord::Base
belongs_to :patient_admission
has_many :vital_signs, :dependent => :destroy
accepts_nested_attributes_for :vital_signs, :rejects_if => :all_blank, :allow_destroy => true
attr_accessible :vital_signs_attributes
end
And my app/models/vital_sign.rb looks like:
class VitalSign < ActiveRecord::Base
belongs_to :admission_record
attr_accessible # just fields that appear in the form
end
The Controller:
The new and create methods in my AdmissionRecordsController looks like:
before_filter do
#admission = PatientAdmission.find(params[:patient_admission_id])
end
def new
#record = #admission.admission_records.build
end
def create
#record = #admission.admission_records.build(params[:admission_record])
#vital_sign = #record.vital_signs.build(params[:vital_signs])
#vital_sign.save
if #record.save
# Flash success and redirect to the right place
else
# Flash error and render :new
end
end
The Plea:
Please help me find where I'm going wrong. I've googled for hours and have looked at other examples and source code for demo apps such as those found in cocoon_simple_form_demo, but still can't seem to fix this error. If there's any other piece of information needed to debug this problem, please let me know. Thanks!
Okay I just had this problem and fixed it by entering one line of code in the belongs_to model.
# patient_admission.rb
Class PatientAdmission < ActiveRecord::Base
attr_accessible :admission_record_attributes
accepts_nested_attributes_for :admission_record
...
end
Here is another solution to it :)

carrierwave cache images and activerecord

I am using Rails 3 and carrierwave gem.
My problem is the next:
I am coding a wizard form with multiple models and relations. So My application has products which has many images through Image model (Its has been mounted with carrierwave).
Because the form has many steps I want save temporaly the images with cache option in CarrierWave. then i last step i want recover the images and load my product. So I create a model called TempData which save temporaly data (In this case cache_name), a type_identifier and a mark can_be_deleted.
For example these are my models:
Product Model:
class Product < ActiveRecord::Base
has_many :images, :as => :imageable, :dependent => :destroy
def save_images_in_temporal_folder(images_attributes)
begin
uploader = ImageUploader.new
images_attributes.to_hash.each do |image|
uploader.cache!(image[1]['filename'])
TempData.create(:data => uploader.cache_name, :can_deleted => false, :type_name => TempDataType.product_image_upload_to_words)
end
rescue
end
end
def load_images_from_temporal_folder
begin
uploader = ImageUploader.new
tmp_images = []
TempData.find_all_by_can_deleted_and_type_name(false, TempDataType.product_image_upload_to_words).map(&:data).each do |cache_name|
tmp_images << uploader.retrieve_from_cache!(cache_name)
end
tmp_images
rescue
end
end
end
Image model
class Image < ActiveRecord::Base
attr_accessible :imageable_type, :imageable_id, :filename
belongs_to :imageable, :polymorphic => true
mount_uploader :filename, ImageUploader
#validates :filename, :presence => true
end
My ImageUploader:
class ImageUploader < CarrierWave::Uploader::Base
configure do |config|
config.remove_previously_stored_files_after_update = false
end
include CarrierWave::RMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def self.store_dir_for_file(model, mounted, filename, version = "")
filename = "#{version}_#{filename}" unless version.blank?
"uploads/#{model.class.to_s.underscore}/#{mounted}/#{model.id}/#{filename}"
end
process :resize_to_limit => [200, 300]
version :thumb do
process :resize_to_limit => [50, 50]
end
version :big do
process :resize_to_limit => [400, 400]
end
def extension_white_list
%w(jpg jpeg gif png)
end
end
So How i save/cache the images with model and mount information?. How retrieve the cache and load my product with images in cache?
Thanks in advance. Sorry for my english and if you need more information comment this post.
View the next link:
CarrierWave with ActiveResource
Also I create a model which storage temporal data. Here I save the cache_name of carrierwave. When i save the product mark these register as can_be_deleted. Then I write a task which delete these registers and clean Carrierwave cache files.

How to update a polymorhic model

I have a polymorhpic model as follows:
class Upload < ActiveRecord::Base
belongs_to :uploadable, :polymorphic => true
has_attached_file :photo
end
class Message < ActiveRecord::Base
has_one :upload, :as => :uploadable, :dependent => :destroy
end
The user uploads a photo in a fancy box iframe using the ajax hack with the jquery-file-upload plugin.
The uploaded photo is saved in the uploads table without uploadable_id or uploadable_type as I don't have the parent Message yet.
How can I update the Upload model with the Message id and type when I save the Message?
You can try this:
#message = Message.new(params[:message])
#message.upload = #upload
#message.save