ActiveRecord has many awesome validators for common things like presence, numericality, etc. Unfortunately, it is missing one common format - regex, or regular expressions. These are normally saved as string fields and, if not validated, can lead to page errors when your app tries to use a field that contains an invalid regular expression. This is especially the case if you allow the user to input a regular expression. With the addition of one small validation class, you will be able to prevent these sorts of bugs with your models.
The above code adds a validator called RegularExpressionValidator to app/validators/regular_expression_validator.rb. It then adds the validation to the Bear model on the field my_regex_field. With this, if you try and create a Bear with an invalid regular expression, an error will be thrown and the save will not complete.
A blog about the problems I've encountered while being a Ruby on Rails developer, and how I've solved them.
Showing posts with label Models. Show all posts
Showing posts with label Models. Show all posts
Wednesday, March 18, 2015
Monday, February 2, 2015
Updating a Rails Model with a Non-default Primary Key
In my last post, I talked about creating a Rails model with a non-default primary key. You can create new instances of the model with no problem, but what happens when you want to update an instance of the model?
Fortunately, there is an easy fix. You just have to specify the column name of the primary key from within the model.
TypeError: nil is not a symbol nor a string
Oh no!!!!Fortunately, there is an easy fix. You just have to specify the column name of the primary key from within the model.
class BearHabitat < ActiveRecord::Base
self.primary_key = 'bear_id'
end
Now you should be able to update your model within your code with no problem. Why does this happen in the first place? My guess is that somewhere within ActiveModel, it assumes that the primary_key field is set. Since your migration set id to false, this value gets defaulted to nil. If you don't manually set it, ActiveModel gets sad. Now you can make ActiveModel happy again.
Saturday, January 31, 2015
Creating a Rails Model with a Non-default Primary Key
One of the main Rails philosophies is "convention over configuration". This works great most of the time, but sometimes it's best to do something outside of convention. One example is the primary key for models. Sometimes you want the key to be something other than ID; maybe you want it to be the ID of a related model.
This is possible to set up in a migration, you just need to do a few important things:
- Set id: false on the create_table line
- Set your new primary key to null: false
- Add a unique index on your new primary key
Here is an example:
class CreateBearHabitats < ActiveRecord::Migration
def change
create_table :bear_habitats, id: false do |t| // prevents a default ID column from being created
t.belongs_to :bear, null: false //creates a bear_id column that can not be null
t.string :habitat
end
add_index :bear_habitats, :bear_id, unique: true // ensures that the bear_id column is unique
end
end
This BearHabitat model will now use bear_id as a primary key instead of the standard id.
Monday, January 19, 2015
Testing Loaded Devise Modules In Your Models
So you're using Devise or devise_token_auth for user authentication in your Rails project. Awesome! Both are great libraries for authentication. Now, how are you testing your code? You probably have feature tests to ensure tasks like creating a new user work (and if you don't, stop reading this right now and make them!). You might even have controller tests to ensure, for example, that each action authenticates the user before proceeding.
Devise provides a method called devise_modules that returns an array of symbols representing the modules that you include. With this, you can easily test that you're using only these two modules by doing this:
What if there was a business requirement that Omniauth was not available? Well, you can test that easily too:
What about your models? They are important too, and fortunately these libraries handle most of the model work in the background for you. There are still things you can test though! The main thing that come to mind are ensuring that you only load the devise modules that you want. For devise_token_auth, you also want to ensure you load the model concern.
Devise Modules
Let's say that you're only using the Database Authenticateable and Registerable modules. With Devise, your model might look something like this:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable
end
Devise provides a method called devise_modules that returns an array of symbols representing the modules that you include. With this, you can easily test that you're using only these two modules by doing this:
// spec/models/user_spec.rb
// using RSpec and FactoryGirl for testing
RSpec.describe User do
it 'has the right devise modules loaded' do
user = FactoryGirl.build(:user)
expect(user.devise_modules).to eq([:database_authenticatable, :registerable])
end
end
What if there was a business requirement that Omniauth was not available? Well, you can test that easily too:
it 'does not load the Omniauth module' do
user = FactoryGirl.build(:user)
expect(user.devise_modules.include?(:omniauthable)).to be_falsey
end
DeviseTokenAuth concern
With devise_token_auth, you also include a concern to add extra methods to User that are used internally. How can you test this? Easily!
it 'loads the DeviseTokenAuth concern' do
expect(User.ancestors.include?(DeviseTokenAuth::Concerns::User)).to be_truthy
end
Summary
With these tests, you can be sure that your model includes everything from Devise that you're expecting it too. This is great insurance for when you decide to refactor your model 6 months from now. It makes your assumptions clear, ensures that any changes are explicit, and allows you to test your user model is using Devise without having to run your expensive feature specs.
Subscribe to:
Posts (Atom)