Rails controller checking for information already in the table - ruby-on-rails

How does one check to see if some data already exists in one of the tables in the controller?
So for example lets say in the create action you want to prevent the following from happening:
#equip = #petowner.equips.new(params[:equip])
this variable contains data that already exists in the equips table.
I would like to prevent the data of a given inventory from being applied a second time.
while #intable == 1, #intable not end of file, #intable++
if #equip.inventory_id == #intable.inventory_id
# Render a failure message that returns back to new saying that this data already has been applied to a a given pet.
end
If it succeds and doesn't find the information then it should continue on forward.
In Equips controller is where I want the check to occur, but don't know how to accomplish it is Rails 3.2.13
Any ideas?

You could use the .exists?() function
if Model.exists?(id) then
#do stuff
end
You might want to also put some validations in the model itself, such as validates uniqueness:
class Account < ActiveRecord::Base
validates :email, uniqueness: true
end

Related

ActiveRecord, validates_uniqueness_of :name not catching non-uniquness if I have a capitalize method

I have a simple capitalize method so that when user submits a new band in the band page it returns it with the first letter capitalized.
Inside my Band class I also have a validates_uniqueness_of :band_name to see if there is already a band with the same entry. See code below:
class Band < ActiveRecord::Base
has_and_belongs_to_many :venues
validates :band_name, :presence => true
before_save :title_case
validates_uniqueness_of :band_name
private
def title_case
self.band_name.capitalize!
end
end
So if I type in someband, it creates it and displays it as Someband. If I type someband again, ActiveRecord sees it as unique and I'll get another Someband. The only way it works is if I type Someband. How would I remedy this situation?
I think what you want to do is this
validates_uniqueness_of :band_name, :case_sensitive :false, allow_blank: false
Take a look at http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html
:case_sensitive - Looks for an exact match. Ignored by non-text
columns (true by default).
The reason your code doesn't work is because validations happen before the before_save callbacks are triggered. Check out the list of ActiveRecord::Callbacks for the order in which things are called.
MZaragoza's answer is a great option for making your validation work regardless of what casing your users might enter. It will prevent things like "someband" and "SomeBand" from being added. I recommend including that as part of your solution.
Another option very similar to the code you already have is to switch to using the before_validation callback:
before_validation :title_case
I highly recommend using the before_validation callbacks instead of before_save callbacks whenever data changes that may be relevant to your validation rules, regardless of what other changes you make. That ensures that you are checking that actual state of the model that you plan to save to the database.
You can use attribute setter instead of before_save callback to capitalize your value without postponing.
def band_name=(value)
self['band_name'] = value && value.mb_chars.capitalize
end

Check if record exists before creation

I have a subscribe method in my controller
def subscribe
#subscription = current_user.subscriptions.create(params[:subscription])
#subscription.title = #stream.title
#subscription.save
redirect_to stream_path(#stream)
end
Before I set the subscription title to the stream title, how can I check if a subscription already exists with the same title?
Like so :
current_user.subscriptions.where(title: #stream.title).present?
But assuming you only want to save it if it is not included elsewhere you can do this :
if current_user.subscriptions.where(title: #stream.title).blank?
#subscription.title = #stream.title
#subscription.save
end
An elegant way to perform this is to add the logic to your controller so that it validates uniqueness ( and also prevents race conditions ) :
class Subscription < ActiveRecord::Base
validates_uniqueness_of :title, scope: :user
end
And then you can check validation in model.save ( again, assuming you don't want it to save if it shares the same title )
To help you out, the suggestion by #Sergio Tulentsev basically means you create a unique index on a column in your db, like this:
#db/migrate/[timestamp]_new_migration.rb
add_index :table, :column, unique: true
This creates an index on your data table, which basically means you cannot make any duplicate data in it. The bottom line - it means you can only insert the data once.
--
The save! method is there to update your record if it exists already. First time I've seen this method, so it's been a good lesson for me. If you're having problems with it, it will probably be that your database will not have the index you need

Rails asking for a secret key to create model

I am creating a simple blog / news website without a user authentication system. I've decided to a use plain some sort of secret key checking technique to allow visitors who know the key to make posts.
In short, to post, you have to provide a key. Otherwise, it object should not be saved into the db.
Here's my code.
class Post < ActiveRecord::Base
attr_accessor :slaptazodis
validate :passcheck
validates :title, presence: true
validates :body, presence: true
def passcheck
if :slaptazodis != "1234"
errors.add(:base, 'Invalid pass')
end
end
end
So, I create a new model in sandbox with title, body and attribute slaptazodis set to 1234. Still, when I check errors, console keeps showing me "Invalid pass". What am I doing wrong? Is it about attributes or something? Thank you in advance :)
You should consider putting that logic away from the post model and moving it to the controller.
In the controller you could check the parameters sent by an user eg.
if params[:slaptazodis] != "1234"
If however, you're learning rails and just want to make it work with your existing solution, change from:
if :slaptazodis != "1234"
to:
if slaptazodis != "1234"
The ":" tells Rails that it should consider the characters following a symbol (almost the same as a string) just for clarification, your code is therefore almost the same as say:
if "slaptazodis" != "1234"
Which of course always renders true.

How can I skip a specific validation when importing data?

How can I skip a specific model validation when importing data?
For example, suppose I have this model:
class Account
validates :street_address, presence: true
end
Normally, I don't want accounts to be saved without addresses, but I'm also going to convert a lot of data from an old system, and many accounts there don't have addresses.
My goal is that I can add the old accounts to the new database, but in the future, when these accounts are edited, a street address will have to be added.
Clarification
As I said, I want to skip a specific validation; others should still run. For example, an account without an account number shouldn't be loaded into the new system at all.
This should work:
class Account
attr_accessor :importing
validates :street_address, presence: true,
unless: Proc.new { |account| account.importing }
end
old_system_accounts.each do |account|
# In the conversion script...
new_account = Account.new
new_account.importing = true # So it knows to ignore that validation
# ... load data from old system
new_account.save!
end
If you're only going to do the conversion one time (i.e, after importing the old data you won't need to do this again), you could just skip validations when you save the imported records instead of modifying your app to support it.
new_account.save validate: false
note that
account.update_attribute(:street_address, new_address)
will skip validations as well. #update_attributes (notice the 's') run validations, where update_attribute (singular) does not.

Validations that rely on associations being built in Rails

A Course has many Lessons, and they are chosen by the user with a JS drag-n-drop widget which is working fine.
Here's the relevant part of the params when I choose two lessons:
Parameters: {
"course_lessons_attributes"=>[
{"lesson_id"=>"43", "episode"=>"1"},
{"lesson_id"=>"44", "episode"=>"2"}
]
}
I want to perform some validations on the #course and it's new set of lessons, including how many there are, the sum of the lessons' prices and other stuff. Here's a sample:
Course Model
validate :contains_lessons
def contains_lessons
errors[:course] << 'must have at least one lesson' unless lessons.any?
end
My problem is that the associations between the course and the lessons are not yet built before the course is saved, and that's when I want to call upon them for my validations (using course.lessons).
What's the correct way to be performing custom validations that rely on associations?
Thanks.
looks like you don't need a custom validation here, consider using this one:
validates :lessons, :presence => true
or
validates :lessons, :presence => {:on => :create}
You can't access the course.lessons, but the course_lessons are there, so I ended up doing something like this in the validation method to get access to the array of lessons.
def custom validation
val_lessons = Lesson.find(course_lessons.map(&:lesson_id))
# ...
# check some things about the associated lessons and add errors
# ...
end
I'm still open to there being a better way to do this.

Resources