I have a HABTM relationship between Products and Categories. Those Categories belongs to a user.
At my product form, I only show checkboxes for the current user. But i want to validate this on model too, so users can't fake POST variables and assign it to invalid categories.
How can i do such validation?
Example: given a category_id 5, i have to check if this category belongs to current_user.id ( provided by devise ).
Thanks.
You can add attr_accessor: creator_id to your Post model. (creator_id is not in database )
And send current_user.id from form to Post's creator_id.
Then use model callbacks. For example after_validation:
after_validation do
if User.find(creator_id).categories.pluck(:id).include?(category_id)
true
else
errors.add :category, "is invalid for user"
end
end
Related
My models: User, Group, and Membership. Users can have many groups through memberships, and vice-versa. I want to create a tool for website admins that produces a large table with the following specification:
Every row represents a user,
Every column represents a group,
In each cell of the table there is a boolean indicating whether the user belongs to the group.
What would be the best way to do this? Is it possible to write a single SQL query that achieves it (i.e. User.find_by_sql)? If not, how else?
p.s. I actually need a bit more than this (I need two columns per group, the first one indicating membership, and the second one counting how many meetings the user has attended in that group, but this involves the Meeting model, so I'll leave that for later.
Assuming that you're asking about the backend methodology not the data visualization aspect most of what JuanM. said is correct. One thing I would recommend is avoid writing his 'get_groups' method and just set up a 'has many through' relationship between users in groups. To do so put
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, through: :memberships
end
In your Users model and vice versa in your Groups model (assuming memberships 'belongs_to' both). Then you'll have a '.groups' method on any User instance and a '.users' method on any Group instance
This would be my approach:
Write a function that returns if the user belongs to a group passed by parameter. Get all the groups from a user. In your user.rb model you can add this method get_groups to retrieve all groups from the user and then a method is_in(group). See code below:
class User < ActiveRecord::Base
#validations, some other stuff
has_many :memberships
#this method stores all the group-ids of the user in an array
def get_groups
myGroups = []
memberships.each do |membership|
membership.groups.each do |group|
myGroups << group.id
end
end
return myGroups
end
#this method receive a Group object and return true if the user belongs to that group
def is_in(group)
groups = get_groups
return groups.include?(group.id)
end
Then in your view or controller you can work as follow:
#the columns of the table
groups = Group.all
#iterating all users
User.all.each do |user|
#each user has to see if it belongs to each group in the groups table
groups.each do |group|
#the boolean value you display in a cell
value = user.is_in(group)
end
end
I have an associations like:
class Contact
has_many :addresses
has_many :email_addresses
has_many :phone_numbers
end
I want to save all the records (address, email and phones) in once single save statement. For that I wrote following code.
contact = Contact.new(contact_params)
contact.addresses.build(address_params1)
contact.addresses.build(address_params2)
contact.email_addresses.build(email_params1)
contact.email_addresses.build(email_params2)
contact.phone_numbers.build(phone_params1)
contact.phone_numbers.build(phone_params2)
contact.save
It does save the contact, but not saving other records. What am I missing here?
NOTE: I am not using any form to save data. I am importing data.
Add validates_associated in your contact model and then check
validates_associated :addresses, :email_addresses, :phone_numbers
First, In my opinion, you just CAN'T do that.
If you want to save addresses, you need a contact_id for each of them.
And, when you save contact, rails will first validate contact and all sub-objects. This means
contact.valid? must be true before you can save any record.
Since contact does not have an id before save to db, contact_id in any of addresses is empty.
Therefore, contact.valid? will always be false as long as you need to CREATE new contact and its sub-objects at the same time
To summarize, here is the steps of rails:
validate contact itself, success!(NOTE: note saved)
validate address for each of contact.addresses, contact_id not provided, fail!
Second, my suggestion about your problem
About your problem "It does save the contact, but not saving other records.", you need to tell rails that you want to save sub-objects(as shown bellow). Otherwise, rails will ignore other objects. However, even though you did this, you would also meet the problem I described above.
#contact.rb
accepts_nested_attributes_for :addresses
...
My suggestion: you can use transaction.
creat contact
build all sub-objects
save contact again
code sample:
#contacts_controller.rb
Contact.transaction do
contact = Contact.new(contact_params)
contact.addresses.build(address_params)
...
contact.save
end
I have two models, Invitation and RSVP. An invitation has many rsvps and rsvp belongs to an invitation. I want to run a query that will return all invitations and the rsvps that belong to each invitation. I want to have all the attributes that belong to both invitation and rsvp. I'm aware of includes and have been trying things like
#results = RSVP.where(user_id: 3).includes(:invitation)
but I'm only getting the attributes of RSVP returned. I ideally want to have the attributes of the Invitation that RSVP belongs to added to the results. What concept am I missing or should I think of this a different way?
Let us assume that the Invitation model has two fields event_name and event_date that you want to access in your query results. You can customize the select list if provide a joins clause.
RSVP.select("rsvps.*, invitations.event_name invitation_event_name,
invitations.event_date invitation_event_date"
).where(user_id: 3).joins(:invitation).each do |rsvp|
puts rsvp.invitation_event_name, rsvp.invitation_event_date
end
RSVP.where(...) with or without the includes(...) is going to return a collection of RSVP objects. By including the :invitation association each RSVP has, you're eager-loading the :invitation for each RSVP in the collection all at once. This prevents a separate SELECT * FROM invitations WHERE ... query from being run for every RSVP in the collection when you refer to it's :invitation association.
.includes is nothing but a query optimization if you plan on using an association for objects within a collection. It does not merge attributes from the association into the model instances in the result set.
If you want to have an attribute from the associated Invitation included on the RSVP instances, you can use Rails delegate method. You can read about it here.
On your RSVP model you'd do something like this, listing out the desired attributes from Invitation in place of the placeholders I've left below.
class RSVP < ActiveRecord::Base
has_one :invitation
delegate :some_invitation_attribute, :another_invitation_attribute, to: :invitation
Now you can call :some_invitation_attribute and :another_invitation_attribute directly on an RSVP instance.
#results = RSVP.where(user_id: 3).includes(:invitation)
puts #results.first.some_invitation_attribute # delegates the .some_invitation_attribute method call to the associated Invitation
In my model(Product) i have a validation, that each product should have a valid owner (login_id of user)
validates_presence_of :owner
validates_inclusion_of :owner, :in => User.first.login_id, :message => "%{value} is not a valid owner name"
I am trying to create product mock object using factory girl
for creating a new product I need login_id of a user.
to do so i have create a user.
up to this every thing is ok, but when i am trying to create a Product using that user's login_id
product is not create, and displaying validation message ("User1 is not a valid owner name").
After digging into deeper i found that
Problem arise from validation in my model.
I have a validation (validates_inclusion_of :owner, :in => User.first.login_id) which initialize before creating the mock user in factory.rb,
(up to that time no user is created in database, user is created after initialization of model when it execute factory.rd )
My question is:
1. How do I able to create a user before initialization of model.
Can you not create a user object, and then pass that object to your product factory? This should create a valid user and then supply it through the owner association and make the product valid.
user = Factory(:user, :name => "User1")
product = Factory(:product, :owner => user)
This user apparently has to be the first user too? So if you have existing user objects then you can try clearing all users before you create the first one.
User.delete_all
I solve this problem as follows:
In my model I have replaced the 'Rails validation' by writing Custom validation method. This custom validation method will be called at the time of creating 'Product'.
validates_presence_of :owner
validate :owner_should_be_registered_user
def owner_should_be_registered_user
if !User.all_user.include? owner and !owner.nil?
errors.add(:owner, "is not a valid user")
end
end
Im building an app where Users have some sort of wishlist
a User can have only one wishlist, and can add existing Items to that wishlist
however the Items belong to other Users on the site
I need to be able to access the wishlist items through current_user.wishlist.items (im using Devise so current_user is available)
i though of adding a wishlist_id column to the items table, but that wouldnt work since items can belong to multiple wishlists.
this seems simple but im having a hard time visualizing the relationship or the migration im supposed to generate
class User < ActiveRecord::Base
has_one :wishlist # or belongs_to :wishlist, it depends which you prefer
end
class Wishlist < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :items
end
And of course:
./script/rails generate migration create_item_wishlists wishlist_id:integer item_id:integer
to create join table between items and wishlists.
UPDATE: To answer "frank blizzard" question in comment:
Let's say you have the same structure as in my answer (just change Item to Product or other model name), with HABTM relationship you just need to add new "item" to collection of "items", and then save wishlist:
#user.wishlist.items << item
#user.wishlist.save
You can make it method in user:
class User
def add_to_wishlist(item)
wishlist.items << item
end
end
If you want to remove or modify collection of "items", just use any Ruby method from Array and then save wishlist, which will check differences for you and save only changes.