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
Related
I have an Article model and Ckeditor + Paperclip installed. When I upload pictures into Article body, everything works fine. However, I want to make these pictures accessible via #article.pictures without creating a separate Picture model. I've already created a regular association between Article and Ckeditor::Picture. But when I'm uploading a picture, Ckeditor not surprisingly requires an Article id. Where and how am I supposed to pass it?
class CreateCkeditorAssets < ActiveRecord::Migration[5.2]
t.references :article, foreign_key: true
end
class Article < ApplicationRecord
has_many :pictures, class_name: 'Ckeditor::Picture'
end
class Ckeditor::Picture < Ckeditor::Asset
belongs_to :article
end
You can't pass an article ID, because at the time when you upload pictures your article isn't persisted (unless you're editing an already saved article).
So what you can do is to build an article with some unique token, then after uploading pictures and saving the article, update article_id in all pictures that have the same token.
Like this: (pseudocode, not tested)
class Article < ApplicationRecord
has_many :pictures, class_name: 'Ckeditor::Picture'
after_save :assign_pictures
private
def assign_pictures
Ckeditor::Picture.where(token: picture_token).update_all(article_id: id)
end
end
-
class Ckeditor::Picture < Ckeditor::Asset
belongs_to :article, optional: true
end
-
class Ckeditor::PicturesController
def create
#picture = Ckeditor::Picture.new
#picture.token = params[:picture_token] # pass this param via javascript, see: https://github.com/galetahub/ckeditor/blob/dc2cef2c2c3358124ebd86ca2ef2335cc898b41f/app/assets/javascripts/ckeditor/filebrowser/javascripts/fileuploader.js#L251-L256
super
end
end
-
class ArticlesController < ApplicationController
def new
#article = Article.new(picture_token: SecureRandom.hex)
end
end
Obviosly you need to add picture_token field to your Article model and token field to Ckeditor::Picture. Hope that helps.
Looking for a cleaner way to set a default value if attribute is not set yet or has been deleted, and returns nil.
class Category < ActiveRecord::Base
has_and_belongs_to_many :restaurants
belongs_to :picture
def set_picture
if self.picture.nil?
Picture.default_pic
else
self.picture
end
end
end
class Picture < ActiveRecord::Base
belongs_to :review
def self.default_pic
Picture.new(url: "/assets/default.jpg")
end
end
# index.html.erb
<%= image_tag category.set_picture.url %>
categories has many restaurants, and restaurants has many reviews. Reviews has one to one picture. category should be allowed to select from one of its associated pictures, or defaults to image in assets folder.
The #set_picture needs to get refactored out. Hopefully to a callback of some type:
class Category < ActiveRecord::Base
belongs_to :picture, defaults_to: Picture.default_pic
end
Is there a callback that does the above? Can I create one? Or is my framework wrong?
I think you could just override the accessor and call super. If this returns nil then you could return your default picture:
class Category < ActiveRecord::Base
belongs_to :picture
def picture
super || Picture.default_pic
end
end
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
I have two models, each with their own Carrierwave uploaders:
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
end
and:
class Bookshelf < ActiveRecord::Base
mount_uploader :image, ImageUploader
end
I want the user's avatar to be the latest bookshelf image he's uploaded. I try to achieve this like so:
class BookcasesController < ApplicationController
def create
#bookcase = current_user.bookcases.build(params[:bookcase])
if #bookcase.save
current_user.avatar = #bookcase.image
current_user.avatar.recreate_versions!
end
end
end
Unfortunately, this has no effect on the avatar at all. How else might I achieve this?
current_user.avatar = #bookcase.image
current_user.avatar.recreate_versions!
Doesn't actually save --- you can either:
current_user.avatar.save
or as you put:
current_user.update_attribute(:avatar, #bookcase.image)
If your image file is stored locally and you don't mind opening a file descriptor, you could also do this:
current_user.avatar = File.open(#bookcase.image.path)
current_user.save
For example there are some models
class Model_1 < ActiveRecord::Base
has_many :images, :as => :imageable
end
class Model_2 < ActiveRecord::Base
# doesn't have has_many association
end
...
class Image < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
How can I check that model has has_many association? Something like this
class ActiveRecord::Base
def self.has_many_association_exists?(:association)
...
end
end
And it can be used so
Model_1.has_many_association_exists?(:images) # true
Model_2.has_many_association_exists?(:images) # false
Thanks in advance
What about reflect_on_association?
Model_1.reflect_on_association(:images)
Or reflect_on_all_associations:
associations = Model_1.reflect_on_all_associations(:has_many)
associations.any? { |a| a.name == :images }
I found the following to be the simple way to achieve the desired result:
ModelName.method_defined?(:method_name)
Example:
Model_1.method_defined?(:images) # true
Model_2.method_defined?(:images) # false
Reference: https://stackoverflow.com/a/18066069/936494
You could probably use respond_to?
class ActiveRecord::Base
def self.has_many_association_exists?(related)
self.class.associations.respond_to?(related)
end
end
You could just have a method that tries to access a Model_1 object images inside an exception block like (roughly) :
begin
model1_obj.images
rescue
puts 'No association between model_1 and images'
end
Inside rescue, you can just return false if you like.