Ruby has two different ways to match the start and the end of a text:
^
(Start of line) and $
(End of line)\A
(Start of string) and \z
(End of string)Most often you want to use \A and \z.
Here is a short example in which we want to validate the content type of a file attachment. Normally we would not expect content_type_1
to be a valid content type with the used regular expression image\/(jpeg|png)
. But as ^
and $
will match lines, it matches both content_type_1
and content_type_2
. Using \A
and \z
will wo...
validates_uniqueness_of
is not sufficient to ensure the uniqueness of a value. The reason for this is that in production, multiple worker processes can cause race conditions:
users
table and see that the name is availableCalling bundle update GEMNAME
will update a lot more gems than you think. E.g. when you do this:
bundle update cucumber-rails
... you might think this will only update cucumber-rails
. But it actually updates cucumber-rails and all of its dependencies. This will explode in your face when one of these dependencies release a new version with breaking API changes. Which is all the time.
In the example above updating cucumber-rails
will give you Capybara 2.0 (because capybara
is a dependency of `cucumber-rail...
Calling bundle update
(without arguments) updates all your gems at once. Given that many gems don't care about stable APIs, this might break your application in a million ways.
To stay sane, update your gems using the applicable way below:
Update the entire bundle regularily (e.g. once a week). This ensures that your libraries are up-to-date while it's easy to spot major version bumps which may break the app.
TLDR: In tests you need to clean out the database before each example. Use :transaction
where possible. Use :deletion
for Selenium features or when you have a lot of MyISAM tables.
You want to clean out your test database after each test, so the next test can start from a blank database. To do so you have three options:
DatabaseCleaner.strategy = :transaction
or `config.use_transactional_fi...To add a few basic styles to the default error pages in Rails, just edit the default templates in public
, e.g. public/404.html
.
A limitation to these default templates is that they're just static files. You cannot use Haml, Rails helpers or your application layout here. If you need Rails to render your error pages, you need the approach below.
Git commits should be very deliberate, and only contain changes that you really want to be in there. In order to reduce the chance to accidentally commit something you didn't intend, review your changes before committing.
git add -N . # Add all paths, but not their contents
git add -p
Git will now show you all your changes in small chunks and ask you in an interactive mode whether you really want to add them.
The most helpful commands are
ActiveRecord has a feature called counter caching where the containing record in a has_many
relationship caches the number of its children. E.g. when you have House has_many :rooms
, Rails can cache the number of rooms in House#rooms_count
.
Mind that when a model has a column that looks to Rails like a counter-cache column, Rails will apply counter-cache logic to your model, even if you're not using counter caches.
E.g. you have a house with 12 rooms, but `house.r...
When you have two models in a has_many
, has_one
or belongs_to
association, the :inverse_of
option in Rails tells ActiveRecord that they're two sides of the same association.
Example with a has_many
/ belongs_to
association:
class Forum < ActiveRecord::Base
has_many :posts, inverse_of: :forum
end
class Post < ActiveRecord::Base
belongs_to :forum, inverse_of: :posts
end
Knowing the other side of the same association Rails can optimize object loading so forum
and forum.posts[0].forum
will reference the same o...
simple_format
ignores Rails' XSS protection. Even when called with an unsafe string, HTML characters will not be escaped or stripped!
Instead simple_format
calls sanitize
on each of the generated paragraphs.
ActionView::Base.sanitized_allowed_tags
# => #<Set: {"small", "dfn", "sup", "sub", "pre", "blockquote", "ins", "ul", "var", "samp", "del", "h6", "h5", "h4", "h3", "h2", "h1", "span", "br", "hr", "em", "address", "img", "kbd", "tt", "a", "acrony...
Note: Modern Rails has two build pipelines, the asset pipeline (or "Sprockets") and Webpacker. The principles below apply for both, but the examples shown are for Sprockets.
Every page in your application uses many assets, such as images, javascripts and stylesheets. Without your intervention, the browser will request these assets again and again on every request. There is no magic in Rails that gives you automatic caching for assets. In fact, if you haven't been paying attention to this, your application is probabl...
With the the ruby Tempfile class you can create temporary files. Those files only stick around as long as you have a reference to those. If no more variable points to them, the GC may finalize the object at some point and the file will be removed from the filesystem. If you would try to access your tempfile then using its path (which you stored previously), you would get an error because the file no longer exists.
Unlink your tempfiles when you're done with them
-...
In a nutshell: Use git rebase --onto target-branch source-commit
target-branch
means "branch you want to be based on"source-commit
means "commit before your first feature commit"Let's say my-feature-branch
is based on master
and we want it to be based on production
. Consider this history:
%%{init: { 'gitGraph': {'showCommitLabel': true, 'mainBranchName': 'production'}} }%%
gitGraph
commit id: "1"
commit id: "2"
branch master
commit id: "3"
commit id: "4"
branch my-feature...
When deploying, Capistrano puts a REVISION
file into your application's release directory. It contains the hash of the commit which was deployed.
If you want to know the currently deployed release, simply SSH to a server and view that file.
$ cat /var/www/my-project/current/REVISION
cf8734ece3938fc67262ad5e0d4336f820689307
When your application is deployed to multiple servers, you probably want to see a result for all of them.
Here is a Capistrano task that checks all servers with the :app
role.
ActiveSupport comes with a #transliterate
method which replaces characters with their low-ASCII equivalent (to strip accents etc.:):
ActiveSupport::Inflector.transliterate('aäoöuü') # => "aaoouu"
You can also add custom rules in your I18n dictionary like this:
de:
i18n:
transliterate:
rule:
Ä: 'Ae'
Ö: 'Oe'
Ü: 'Ue'
ä: 'ae'
ö: 'oe'
ü: 'ue'
ß: 'ss'
With this you get:
ActiveSupport::Inflector.transliterate...
Recent rails security updates have shown that people make incorrect assumptions about the possible contents of the params
hash.
Just don't make any! Treat it as what it is: potentially unsafe user input. For example:
/pages/edit?foo --> params == {:foo => nil}
/pages/edit?foo[] --> params == {:foo => [nil]} # at least in older rails 3 and in rails 2.x
Be especially wary about stuff like
User.find_by_password_reset_token(params[:password_reset_token])
If params[:password_reset_token]
is nil
, you'll...
If you're suffering from a huge de.yml
or similiar file, cry no more. Rails lets you freely organize your dictionary files in config/locales
.
My organization works like this:
config/locales/rails.de.yml
modified Rails boilerplate
config/locales/faker.de.yml
modified Faker boilerplate
config/locales/models.de.yml
model names, attribute names, assignable_value labelsLocalizing a non-trivial application can be a huge undertaking. This card will give you an overview over the many components that are affected.
When you are asked to give an estimate for the effort involved, go through the list below and check which points are covered by your requirements. Work with a developer who has done a full-app localization before and assign an hour estimate to each of these points.
app
must be translated: Screens, mailer templates, PDF templates, helpe...When requests arrive at the application servers simultaneously, weird things can happen. Sometimes, this can also happen if a user double-clicks on a button, for example.
This often leads to problems, as two object instances are modified in parallel maybe by different code and one of the requests writes the results to the database.
In case you want to make sure that only one of the requests "wins", i.e. one of the requests is fully executed and completed while the other one at least has to wait for the first request to be completed, you ha...
All our projects have enum-like requirements like this:
<select>
boxes.Most of the time, this requirement is also needed:
In our past projects there are many different solutions for these related requirements, e.g. ChoiceTrait
, methods like `available_...
By default, Google Analytics tracks the current URL for every request. Sometimes you will want to track another URL instead, for example:
Luckily the Analytics code snippet allows you to freely choose what path is being tracked. Simple change this:
ga('send', 'pageview');
......
An association defined with has_many :through
will return the same record multiple times if multiple join models for the same record exist (a n:m relation). To prevent this, you need to add ->{ uniq }
as second argument to has_many
(below Rails 4 it is a simple option: has_many :xyz, :uniq => true
).
Say you have an Invoice
with multiple Items
. Each Item
has a Product
:
class Invoice < ActiveRecord::Base
has_many :items
has_many :products, :through => :items
end
class Item < ActiveRecord::Base
...
You can change which branches will be pushed when saying git push
. Our recommendation is to set it to current
.
From the git-config
documentation:
push.default
: ^
Defines the action git push should take if no refspec is given on the command line, no refspec is configured in the remote, and no refspec is implied by any of the options given on the command line. Possible values are:
nothing
- do not push anything.matching
- push all matching branches. All bra...
The following two hints are taken from Github's Ruby style guide:
If your regular expression mentions a lot of forward slashes, you can use the alternative delimiters %r(...)
, %r[...]
or %r{...}
instead of /.../
.
%r(/blog/2011/(.*))
%r{/blog/2011/(.*)}
%r[/blog/2011/(.*)]
If your regular expression is growing complex, you can use the /x
modifier to ignore whitespace and comments or use named groups or...