So I have an assets model which is inherited by images and files as STI. Products has many images as assetable. This polymorphic association is working fine but I can't figure out how to add the user_id to every asset. A asset always belongs to a user no matter if its an image or file. Please look at my code below. I'm pretty sure there's something I need to do within the controllers create method but I'm not sure what? I've tried merging :user_id but this just returns nil when looking at the console log. Ideally what I'd also like to do is #user.images which will display all the images that the user has uploaded or even #user.files
class User < ActiveRecord::Base
has_many :products
has_many :assets
end
class Asset < ActiveRecord::Base
belongs_to :assetable, :polymorphic => true
belongs_to :user
end
class Image < Asset
mount_uploader :filename, ImageUploader
attr_accessible :filename, :assets
end
class Product < ActiveRecord::Base
belongs_to :user
has_many :images, as: :assetable
accepts_nested_attributes_for :images
attr_accessible :name, :price, :images_attributes
validates_presence_of :name
end
class ProductsController < ApplicationController
def create
#product = Product.new(params[:product])
#product.user_id = current_user.id
params[:product][:images_attributes].each do |key, image|
# image.user_id = current_user.id
image.merge(:user_id => 1)
end
#product.save
end
end
def create
params[:product][:images_attributes].each do |key, image|
image.merge!(:user_id => current_user.id)
end
#product = Product.new(params[:product])
#product.user_id = current_user.id
#product.save
end
By the way, you'd better to replace inheritance logic into the model:
class Image < Asset
mount_uploader :filename, ImageUploader
attr_accessible :filename, :assets
before_save do
self.user = assetable.try(:user)
end
end
# controller
def create
#product = Product.new(params[:product])
#product.user = current_user
#product.save
end
Related
I want to loop through attributes which are validated with custom validation method.
I have model Post which has_many :languages and a model Language which belongs_to :post. In the languages table I have columns - id, post_id, language.
Post model:
class Post < ApplicationRecord
has_many :languages
accepts_nested_attributes_for :languages, reject_if: :all_blank
validates_associated :languages
end
Language model:
class Language < ApplicationRecord
validate :unique_languages?
def unique_languages?
#LOOP ATTRIBUTES
end
end
IIn the Language model in the unique_languages? I want too loop through all language attributes of the post.
This is posts_controller with strong params and logic for creating a post:
class PostsController < ApplicationController
def new
#post = Post.new
#post.languages.build if #post.languages.empty?
end
def create
#post = Post.new(post_params)
#post.languages.build if #post.languages.empty?
if #post.save
redirect_to action: 'new'
else
render 'new'
end
end
private
def post_params
params.require(:post).permit(:title, languages_attributes: [:language])
end
end
## app/validators/nested_attributes_uniqueness_validator
class NestedAttributesUniquenessValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
raise ArgumentError if options[:parent].blank?
association = record.class.to_s.pluralize.underscore # :languages
items =
record # #language
.send(options[:parent]) # #language.post
.send(association) # #language.post.languages
.select(attribute) # #language.post.languages.select(:language)
unless items.distinct.size == items.size
record.errors.add attribute, :nested_attributes_uniqueness
# Don't forget to translate `errors.messages.nested_attributes_uniqueness`
end
end
end
## app/models/post.rb
class Post < ApplicationRecord
has_many :languages, inverse_of: :post # :inverse_of is important
accepts_nested_attributes_for :languages, reject_if: :all_blank
end
## app/models/language.rb
class Language < ApplicationRecord
belongs_to :post, inverse_of: :languages # :inverse_of is important
validates :language, nested_attributes_uniqueness: { parent: :post }
end
You can access a object attributes by:
class Language < ApplicationRecord
validate :unique_languages?
def unique_languages?
self.attributes.each do |attr, value|
#your code
end
end
end
your object.attributes return a hash where the keys are the attributes names, and the value is the value for that attribute. Don't know exactly what you're trying to do, but this may helps. Good luck!
I have a User and Group model that I bind with an Assignments model. A user has_many groups and a group has_many users. However, when I create a new group, when I do Group.last.users.count the output is 0 or ActiveRecord::Associations::CollectionProxy []. Do I need to change an aspect of my simple_form? Did I not build the middleman model correctly to bind users and groups? I would like it so that when a user creates a group, the group_ids are in the array when doing User.last.groups, etc. When I had it as User has_many groups and a Group belongs_to user, the group ids would be tied to a user. But since switching to has_many for both models and introducing the Assignments model, this is no longer the case.
Group Model
class Group < ActiveRecord::Base
validates :user_id, presence: true
has_many :assignments
has_many :users, through: :assignments
has_many :posts
has_many :attachments
has_secure_token
end
User Model
class User < ActiveRecord::Base
...
has_many :assignments
has_many :groups, through: :assignments
accepts_nested_attributes_for :assignments
...
Assignment Model
class Assignment < ActiveRecord::Base
belongs_to :group
belongs_to :user
accepts_nested_attributes_for :group
accepts_nested_attributes_for :user
end
Groups Controller
class GroupsController < ApplicationController
before_action :authenticate_user!
def new
#group = current_user.groups.build
end
def create
#group = current_user.groups.build(group_params)
#group.user_id = current_user.id
if #group.save
redirect_to groups_path
else
render :new
end
end
private
def group_params
params.require(:group).permit(:group_name, :description, :user_id)
end
end
Group new.html.erb
<%= simple_form_for #group do |f| %>
<%= f.input :group_name %>
<%= f.text_area :description %>
<%= f.button :submit %>
<% end %>
You can do something like that:
I guess the build method seems not saving the joiner model you can use new. There is an issue here:
As there is many-to-many relation between Group and User. Thus there is no need for user_id in group. Thus the validation is unnecessary. And it causes the problem with my first approach. In model comment the validation. # validates :user_id, presence: true
def create
#group = current_user.groups.new(group_params)
# #group.user_id = current_user.id // this line is unnecessary
if #group.save
redirect_to groups_path
else
render :new
end
end
Or, (I'll not suggest it as it is not a good approach)
def create
#group = Group.new(group_params)
if #group.save
current_user.groups << #group
redirect_to groups_path
else
render :new
end
end
I'm not sure what I'm missing here, can anyone point me in the right direction? I set up the initializers and the associations in the model but my JSON is still returning only the attributes inside Active record, including the created_at and updated_at attributes. What am I doing wrong?
ApplicationController.rb
class ApplicationController < ActionController::API
include CanCan::ControllerAdditions
include ActionController::Serialization
acts_as_token_authentication_handler_for User
rescue_from CanCan::AccessDenied do |exception|
respond_to do |format|
format.json { render nothing: true, status: :forbidden }
end
end
end
CompanyController.rb
def show
#logo = Logo.find(params[:user_id])
render json: #logo
end
CompanyModel.rb
class Company < ActiveRecord::Base
belongs_to :user
has_one :logo, dependent: :destroy
has_many :cards, dependent: :destroy
end
LogoModel.rb
class Logo < ActiveRecord::Base
belongs_to :company
mount_uploader :image, ImageUploader
end
CompanySerializer.rb
module V1
class CompanySerializer < ActiveModel::Serializer
attributes :id, :user_id, :name
has_one :logo
end
end
LogoSerializer.rb
module V1
class LogoSerializer < ActiveModel::Serializer
attributes :id, :company_id, :image_url
end
end
EDIT: I should have posted the CompanyController Action, not the LogoController. I've added it above and added the LogoSerializer
I have three models User, Blog and Comment.
User.rb
class User < ActiveRecord::Base
attr_accessible blah blah
has_many :blogs
has_many :comments
end
Blog.rb
class Blog < ActiveRecord::Base
attr_accessible :user_id, :title, :content
belongs_to :user
has_many :comments
end
Comment.rb
class Comment < ActiveRecord::Base
attr_accessible :user_id, :blog_id, :comment
belongs_to :blog
belongs_to :user
end
In create action of Comments Controller
def create
#blog = Blog.where('id=?', params[:blog_id])
#comment = #blog.comments.new(params[:comment])
#comment.save
end
Here how will I pass id of current_user in the :user_id field of comments table, I can make a hidden field for that but it's not safe. PLease help! Thanks in advance.
Would this do what you want?
def create
#blog = Blog.where('id=?', params[:blog_id])
#comment = #blog.comments.new(params[:comment])
#comment.user = current_user # force the user to be the logged-in user
#comment.save
end
I have Product model like this:
class Product < ActiveRecord::Base
has_many :images, :class_name => 'ProductImage', :order => 'position DESC', :dependent => :destroy
def image_thumb
images.first.image.thumb.url
end
def image
images.first.image.url
end
end
ProductImage model:
class ProductImage < ActiveRecord::Base
attr_accessible :image, :position, :product_id, :title
belongs_to :product
default_scope order('position ASC')
mount_uploader :image, ProductImageUploader
end
Uploader model:
class ProductImageUploader < CarrierWave::Uploader::Base
...
def default_url
asset_path([version_name, "default.jpg"].compact.join('_'))
end
end
But if I don't upload any image for product, I will get 'nil' in image_thumb and image methods. How get default_url if no one image uploaded and relation between Product and ProductImage models are one-to-many?
If you don't have access to an uploader, an uploader can't help you, so you have to do it by hand. You're already using a presenter (more or less), so this is extremely easy:
def image_thumb
if images.any?
images.first.image.thumb.url
else
asset_path("default.jpg")
end
end
def image
if images.any?
images.first.image.url
else
asset_path("thumb_default.jpg")
end
end
Similar code works for belongs_to relationships.
What is the value you are getting for default_url?
Maybe the path is not evaluating correctly.
Try something like this (of course correct the path below to what it should be):
class ProductImageUploader < CarrierWave::Uploader::Base
...
def default_url
"/assets/" + [version_name, "default.jpg"].compact.join('_')
end
end