Following code:
class Product < ApplicationRecord
validates :name, presence: true
validates :price, numericality: {
greater_than_or_equal_to: 0.0
}
validates :description, presence: true
belongs_to :user
def owned_by? owner
user == owner # Where does the user-obj. come from?
end
end
It works. What I don't get is: Where does the "user"-object come from? Please see the line with comment!
"user" is nowhere declared / assigned a value.
Does someone know how that works and can it explain to me?
From the ActiveRecord::Associations::ClassMethods#belongs_to API docs:
Methods will be added for retrieval and query for a single associated
object, for which this object holds an id:
association is a placeholder for the symbol passed as the name
argument, so belongs_to :author would add among others author.nil?.
Example
A Post class declares belongs_to :author, which will add:
Post#author (similar to Author.find(author_id))
...
So in your case, after declaring the belongs_to :user relationship you get that bunch of methods, among them user.
Related
So I have this big headache trying to solve a bug that only happens sometimes... I have the following model for allowing a user to like something:
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :likeable, polymorphic: true
validates :user, uniqueness: {scope: :likeable}
end
This is a set up to allow a user to like multiple other models and has a validation that prevents a user to like the same thing multiple times.
The thing I discovered after debugging is that the SELECT query run by rails seems to check only for the uniqueness of likeable_id (and not likeable_type):
SELECT 1 AS one FROM "likes" WHERE ("likes"."user_id" = 1 AND "likes"."likeable_id" = 4) LIMIT 1
Logically, when a user had already liked a comment with id is 4, he couldn't like any other thing with the same ID.
Any ideas on how to solve this?
According to the docs, you can define uniqueness validation on both type and id:
http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of#893-Does-not-work-with-polymorphic-relations
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :likeable, polymorphic: true
validates :user, uniqueness: {scope: [:likeable_id, :likeable_type]}
end
In my rails projects I have a lot of association tables. And I have some validations. Nothing really difficult, and it works almost every times.
But from time to time (like tonight), I have to switch from
validates_presence_of :project_id
validates_presence_of :tag_id
validates_uniqueness_of :project_id, :scope => [:tag_id]
to
validates_presence_of :project
validates_presence_of :tag
validates_uniqueness_of :project, :scope => [:tag]
Do you know the difference ? Do you if one is better than the other ?
From the Rails Guides: http://guides.rubyonrails.org/active_record_validations.html#presence
2.9 presence This helper validates that the specified attributes are not empty. It uses the blank? method to check if the value is either
nil or a blank string, that is, a string that is either empty or
consists of whitespace.
class Person < ActiveRecord::Base
validates :name, :login, :email, presence: true
end
If you want to be sure that an association is present, you'll need to
test whether the associated object itself is present, and not the
foreign key used to map the association.
class LineItem < ActiveRecord::Base
belongs_to :order
validates :order, presence: true
end
So, you should use the second example you gave, which tests if the associated object itself is present, and not the first example, which only tests if the foreign key used to map the association is present.
I don't know what is the proper manner to ensure that there is only one record with the same couple of foreign keys. Let's assume a class named LineItem, which belongs to an cart and to item. Something like:
class LineItem < ActiveRecord::Base
belongs_to :cart
belongs_to :item
The point is: I want to make unique the combination of this two "attributes". At this time, my approach was using a after_save callback but I realized thats pretty poor. How do you resolve this? I was thinking in a PORO class (something like LineItemSaver) but I'm not completely convinced.
Thanks!
If I understood your question correctly,you want the scope option of the validates_uniqueness_of. If so, this should work.
In your LineItem model:
class LineItem < ActiveRecord::Base
belongs_to :cart
belongs_to :item
validates_uniqueness_of :cart_id, scope: :item_id
end
And also, you should be generating a migration to add this:
add_index :line_items, [ :cart_id, :item_id ], :unique => true
More Info here.
Can't you just do a uniqueness validation?
validates :cart_id, uniqueness: {scope: :item_id}
Try using a validate method to ensure that item_id is unique scoped to :cart_id
Something like:
validates :item_id, uniqueness: { scope: :cart_id }
Or if you want to fix the situation and simply increment the quantity you could also:
validate :ensure_line_item_uniqueness
def ensure_line_item_uniqueness
... whatever fixes the situation here ...
end
My app allows users to add words from a master words table into their own custom list. So, a word list contains multiple custom words each of which link to a master word.
In my view, I have a field called word_text (virtual attribute) where I let users enter a word, and in my model I am trying to look up the master_word_id and set it on the custom word table. I am unable to access the #word_text value in the model. I always seem to get an error that the master word is a required field (because the look up is failing).
class CustomWord < ActiveRecord::Base
attr_accessible :master_word_id, :word_list_id, :word_text
attr_accessor :word_text
belongs_to :word_list
belongs_to :master_word
validates :word_list, presence: true
validates :master_word, presence: true
before_validation :set_master_word
private
def set_master_word
logger.debug "Received word text #{#word_text}"
_mw_id = nil
if !#word_text.nil?
master_word = MasterWord.find_word(#word_text)
if master_word.nil?
errors.add("#{#word_text} is not a valid word")
else
_mw_id = master_word.id
end
end
self.master_word_id = _mw_id
end
end
I sincerely appreciate any suggestions as to how I can set the value of the master_word_id correctly.
There are several things to fix:
class CustomWord < ActiveRecord::Base
attr_accessible :master_word_id, :word_list_id, :word_text
attr_accessor :word_text
belongs_to :word_list
belongs_to :master_word
validates :word_list, presence: true
#validates :master_word, presence: true <= This will always throw error
validates :word_text, presence: true
validates :master_word_id, presence: true
before_validation :set_master_word
private
def set_master_word
logger.debug "Received word text #{self.word_text}"
self.master_word_id = MasterWord.find_by_word_text(self.word_text).id
end
end
Not sure if it will work because I don't know the rest of your app but I hope it points you in the right direction.
I have two models, Rules and Ruleset that both have a has_to_and_belong_to_many relationship. Rules are individual rules, and Rulesets are a specific collection of rules.
The user's dashboard shows all the rules the user created. I have a button for each rule to "Add Rule to Ruleset". By clicking the button, it should load a select form where the user can select their existing rulesets and hit submit, and voila, its added to the ruleset.
I just don't know how to make this work, as I'm pretty new to rails. If I call the update action on rules, it loads the entire update form, which I don't want. I just want to have the ability for a user to select a ruleset and then add that rule to the ruleset. Here are my models:
class Rule < ActiveRecord::Base
attr_accessible :description, :user_id, :game_id, :ruleset_id
has_and_belongs_to_many :rulesets
belongs_to :user
belongs_to :game
validates :description, presence: true
validates :user_id, presence: true
validates :game_id, presence: true
end
class Ruleset < ActiveRecord::Base
attr_accessible :title, :game_id, :user_id, :rule_id
validates :game_id, presence: true
validates :user_id, presence: true
validates :title, presence: true
belongs_to :user
belongs_to :game
has_and_belongs_to_many :rules
end
You should declare a specific action in the controller for adding rules to rulesets.
When a person selects a ruleset, it will be passed as a parameter and you can catch it in your newly declared action. Also, use a hidden_field_tag where you will store your rule_id.
In the newly declared action, create something like this:
def add_rule_to_ruleset
#ruleset = Ruleset.find(params[:ruleset_id])
#rule = Rule.find(params[:rule_id])
#ruleset.rules << #rule
redirect_to current_user.rules
end
Also fetch all the rulesets in the select box with current_user.rulesets, but i guess you will have to check if that ruleset has that rule already (you don't want the same rule twice or more times in the same ruleset, do you? ), so you should modify it.
Check that with something like current_user.rulesets.include?(rule)
Routes.rb:
resources :rules do
member do
put 'add_rule_to_ruleset'
end
end