I have a model named CustomFields that belongs to a main class (that has_many :custom_fields). This model has the attributes contents and datatype. I want the contents to be either a string or a uploader using carrierwave, according to the datatype of the object. I've done the following:
class CustomField < ActiveRecord::Base
after_initialize :set_uploader
def set_uploader
if self.datatype == 'file'
CustomField.mount_uploader :contents, ImageUploader
end
end
end
It's not working because it's turning all the object's contents into uploaders, not only the 'file' datatype. How can I solve that?
Just a guess:
class CustomField < ActiveRecord::Base
mount_uploader :image, ImageUploader, if: :file?
def file?
self.datatype == 'file'
end
end
Related
As of right now, i have a model with a has_one_attached :file which i'm serializing with a method as follows.
# app/models/my_model.rb
class MyModel < ApplicationRecord
has_one_attached :file
def file_url
if file.attached?
Rails.application.routes.url_helpers.rails_blob_url(file)
end
end
end
And then in my serializer with activemodel serializer( JSON API format)
type :my_model
attributes(
:file_url
)
Which works just fine, now i'm moving to a has_many_attached :files, and i'm having problems serializing it. i've tried:
class MyModel < ApplicationRecord
has_many_attached :files
def files_url
files.each_With_object([]) do |file, array|
array << Rails.application.routes.url_helpers.rails_blob_url(file)
end
end
then in my app/controller/my_model_controller.rb
def my_model_params
params.require(:my_model).permit(:files => [])
end
And finally, in my serializer, i just call :files_url(instead of file_url, as i used to, which worked with one file), but it won't work:
type :my_model
attributes(
:files_url
)
Any idea on what am i missing? I can't seem to find much useful info regarding serializing has_many_attached. Thanks
Fixed it! it actually works, i was just sending the wrong params to Insomnia.
I replaced :files => [] in my_model_params with files: []. And in Insomnia i send each file in the my_model[files][] param.
I've been trying to serialize a column before I put it in the database. I wanted to do the following in my model:
class SearchResult < ActiveRecord::Base
serialize :data
end
...but it wouldn't serialize when I save. So I resorted to this:
class SearchResult < ActiveRecord::Base
before_save :serialize_data
private
def serialize_data
self.data = YAML.dump self.data
end
end
This works. But, is there any reason why the top code doesn't work (it's much neater), or do I need to declare the serialize method? It doesn't throw any errors, but doesn't do what I hoped it would do either.
Have you tried:
class SearchResult < ActiveRecord::Base
serialize :data, Hash
end
What about
class SearchResult < ActiveRecord::Base
store :data, accessors: [:data_help]
end
My uploader is working well apart from one small thing. The setting of default images. I'm using carrierwave for users to upload profile images of themselves:
user model
class User < ActiveRecord::Base
has_one :avatar, class_name: 'Image', foreign_key: :user_id
before_create :create_fallback_image
def create_fallback_image
self.create_avatar
end
end
image model
class Image < ActiveRecord::Base
mount_uploader :file_name, AvatarUploader, auto_validate: false
belongs_to :user
end
avatar uploader
class AvatarUploader < BaseUploader
include CarrierWave::RMagick
storage :file
process resize_to_fit: [75, 75]
process convert: 'gif'
def default_url
'foobar'
end
def filename
random_string + '.gif'
end
end
def random_string
#random_string ||= User.random_string
end
end
When a user signs up without uploading an optional profile image, they are assigned an association to their profile image, but instead of the default_url working, they get a random string from the filename method.
I thought I could get around it like this:
user model
class User < ActiveRecord::Base
has_one :avatar, class_name: 'Image', foreign_key: :user_id
before_create :create_fallback_image
def create_fallback_image
# look here:
self.create_avatar.create_fallback
end
end
image model
class Image < ActiveRecord::Base
mount_uploader :file_name, AvatarUploader, auto_validate: false
belongs_to :user
def create_fallback
self.update_attributes(file_name: 'my_fallback.jpg')
end
end
and while it nearly, nearly works, when I update the attributes of the file_name column, the uploader kicks in and my_fallback.jpg is overridden by a random string from my random_string method!
Carrierwave has a built-in fallback mechanism for default image
Update your default_url method in AvatarUploader as below:
def default_url
ActionController::Base.helpers.asset_path("fallback/" + [version_name, "my_fallback.jpg"].compact.join('_'))
end
where change fallback/ to your desired folder path.
This way, when an avatar is not uploaded for a particular user then my_fallback.jpg would be used as fallback image.
Refer to section Providing a default URL in Carrierwave Documentation.
when I update the attributes of the file_name column, the uploader
kicks in and my_fallback.jpg is overridden by a random string from my
random_string method!
This happens because you have overridden filename method in AvatarUploader which gets called every time an image is uploaded. If you notice, its calling random_string method in it. Hence, you get a random string as your filename.
UPDATE
As per the chat session with OP, if an avatar is not uploaded for a user then a default image should be shown. I suggested the following helper :
module ApplicationHelper
def display_avatar(user)
unless user.avatar.nil?
image_tag(user.avatar.file_name)
else
image_tag("/path/to/fallback.jpg")
end
end
## ...
end
Use this helper method in views to display avatar image appropriately.
Also, you can do it within model:
class User < ApplicationRecord
has_one :avatar, class_name: 'User::Avatar', as: :parent, dependent: :destroy
accepts_nested_attributes_for :avatar, allow_destroy: true #, ...
def avatar
super || build_avatar
end
end
I got two models: Source and SourceType. Source of course belongs to SourceType.
I want to create new source and assign proper sourcetype object to it. 'Proper' means that one virtual attribute of the source object match some of sourceType objects test regexpression, which becomes source's Type.
I got an attribute writer in source object
class Source < ActiveRecord::Base
belongs_to :source_type
def url=(value)
SourceType.each do |type|
# here i match type's regexp to input value and if match,
# assign it to the new source object
end
end
end
I don't want to build any custom validator for it'll be need to run through SourceTypes twice. How to raise validate error if no sourcetypes is fit to the input so user could see error reasons in a form?
Validation
If you set the virtual attribute using attr_accessor, you should be able to validate on the model you're sending data to (alternatively using inverse_of if you'd like to validate on the nested model):
http://api.rubyonrails.org/classes/ActiveModel/Validator.html
This can now be used in combination with the validates method (see ActiveModel::Validations::ClassMethods.validates for more on this).
class Person
include ActiveModel::Validations
attr_accessor :title
validates :title, presence: true
end
Code
I'd do this:
class Source < ActiveRecord::Base
belongs_to :source_type, inverse_of: :sources
attr_accessor :url
end
class SourceType < ActiveRecord::Base
has_many :sources, inverse_of: :source_type
validates :source_type_attr, presence: { if: :url_match? }
def url_match?
self.sources.url == [your_regex]
end
end
In my existing Rails project, I create Picture model.
class Picture < ActiveRecord::Base
belongs_to :user
end
And then, when adding Ckeditor to my project, I have to create another Picture model under ckeditor directory like this
class Ckeditor::Picture < Ckeditor::Asset
...
end
In my user model, I have this association
class User < ActiveRecord::Base
has_many :pictures
end
However, I cannot use user.pictures. Whenever I make this statement, the following error comes up:
Expected /home/xxx/app/models/ckeditor/picture.rb to define Picture
How can I solve this issue?
try:
class User < ActiveRecord::Base
has_many :pictures,:class_name=> "::Picture"
end
I'm not sure but maybe:
module Ckeditor
class Picture < Ckeditor::Asset
...
end
end
I managed to resolve my issue by renaming the Picture class into UserPicture and use table_name to set its corresponding table in database. And then in User model:
has_many :pictures, class_name: 'UserPicture'
Simple:
1) rename models/ckeditor/picture.rb to models/ckeditor/epicture.rb
2) in models/ckeditor/epicture.rb change to this:
class Ckeditor::Epicture < Ckeditor::Asset
has_attached_file :data,
url: "/ckeditor_assets/epictures/:id/:style_:basename.:extension",
path: ":rails_root/public/ckeditor_assets/epictures/:id/
3) in config/initializers/ckeditor.rb uncomment row and change to this:
config.picture_model { Ckeditor::Epicture }
4) for correct work in _asset.html.erb change bug:
polymorphic_path(asset, format: :json) to picture_path(asset)
in my case dir of this file
\usr\local\rvm\gems\ruby-1.9.3-p545\gems\ckeditor-4.1.2\app\views\ckeditor\shared\_asset.html.erb
Restart server.
Work's fine!
You can change Dafault Picture Model Name in config/initializers/ckeditor.rb like this:
Ckeditor.setup do |config|
...
config.picture_model { Ckeditor::EditorPicture }
...
end
remove autogenerated defined model from models/ckeditor/picture.rb and add new model /ckeditor/editor_picture.rb
insert to editor_picture.rb
class Ckeditor::EditorPicture < Ckeditor::Asset
mount_uploader :data, CkeditorPictureUploader, :mount_on => :data_file_name
def url_content
url(:content)
end
end