Why has_many :through associations can return the same record multiple times
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
).
Example
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
...
Validate attachment presence using paperclip
Make sure you call the methods in the following order and not vice versa:
has_attached_file :image
validates_attachment_presence :image
Validation with condition works fine, too:
validates_attachment_presence :image, :if => :method
This is because validates_attachment_presence
is only available after saying has_attached_file
.
Shell script to deploy changes to production and not shoot yourself in the foot
Geordi, our collection of command line tools, has been extended by another command deploy-to-production
. This script encapsulates the following workflow:
- Pull the production branch.
- Show which commits from the master would make it to production with this deploy.
- Ask if you want to proceed.
- If yes, merge the master into the production branch, push and deploy with
bundle exec cap production deploy:migrations
The script will ask you for the names of your master branch, production branch an...
validates_acceptance_of is skipped when the attribute is nil
validates_acceptance_of :terms
only works if terms
is set to a value. The validation is skipped silently when terms
is nil
.
While this behavior is useful to validate acceptance in the frontend and not the admin backend, it also makes it very easy to unintentionally skip the validation altogether by forgetting to add the checkbox to a form. E.g. validates_acceptance_of :terms_with_typo
will be skipped silently even if there is no column with t...
Change how Capybara sees or ignores hidden elements
Short version
- Capybara has a global option (
Capybara.ignore_hidden_elements
) that determines whether Capybara sees or ignores hidden elements. - Prefer not to change this global option, and use the
:visible
option when callingpage.find(...)
. This way the behavior is only changed for this onefind
and your step doesn't have confusing side effects. - Every Capybara driver has its own notion of "visibility".
Long version
Capybara has an option (Capybara.ignore_hidden_elements
) to configure the default...
Customize path for Capybara "show me the page" files
When you regularly make use of Cucumber's "show me the page" step (or let pages pop up as errors occur), the capybara-20120326132013.html
files will clutter up your Rails root directory.
To tell Capybara where it should save those files instead, put this into features/support/env.rb
:
Capybara.save_and_open_page_path = 'tmp/capybara'
Connecting the "sequel" gem to MSSQL via ODBC
After you configured your ODBC describe in
- Fix [RubyODBC]Cannot allocate SQLHENV when connecting to MSSQL 2005 with Ruby 1.8.7. on Ubuntu 10.10
- and Connecting to MSSQL with Ruby on Ubuntu - lambie.org
you can connect with sequel
:
require "rubygems"
require "se...
Fix [RubyODBC]Cannot allocate SQLHENV when connecting to MSSQL 2005 with Ruby 1.8.7. on Ubuntu 10.10
I followed this nice guide Connecting to MSSQL with Ruby on Ubuntu - lambie.org until I ran in the following errors:
irb(main):001:0> require "dbi"; dbh = DBI.connect('dbi:ODBC:MyLegacyServer', 'my_name', 'my_password')
DBI::DatabaseError: INTERN (0) [RubyODBC]Cannot allocate SQLHENV
from /usr/lib/ruby/1.8/dbd/odbc/driver.rb:36:in `connect'
from /usr/lib/ruby/1.8/dbi/handles/driver.rb:33:in `connect'
from /usr/lib/ruby...
ActiveRecord: Overwriting a setter causes trouble with attributes depending on each other
Undeterministically I got a nil
error on saving the object caused by the random order of hash elements of the params hash.
class Feedback
belongs_to :user
def role=(value)
@role = value
self.email = find_email_by_name(user.name)
end
end
This piece of code works well until the object params hash contains a second element when it is updated like this:
@feedback.update_attributes!(params[:feedback])
Now it is no longer ensured that user
was set before name
was set. If the name...
Creating the inverse of a Rails migration
Let's say you need to revert a migration that happened a while back. You'd create a new migration that removes what was added back then in the up
path, while its down
path restores the old functionality.
While you could just copy&paste the down
and up
parts of it to the inverse part of the new migration, you may not want to do that. Especially when the up/down paths already contained some logic (that executed update
statements on the created column, for example), copying does not feel right.
Someone already added the logic how to...
Gatekeeping: Guide for developer
If your project manager wants to do gatekeeping on a project, as a developer you need to follow the following guidelines (e.g. by using something like this issue checklist template).
In order to reduce the number of rejects we get from clients, we want to review all code written before it goes to the staging server.
Note: This process is tailored to our specific needs and tools at makandra. While it will certainly not apply to all (especially larger tea...
TeamViewer 7 finally works with multiple screens under Linux
TeamViewer 6 and lower had an issue where they would see a multi-monitor Linux setup as a single wall of pixels. This is fixed in version 7. The guest can now select the currently active screen from the TeamViewer menu.
ActiveRecord: When aggregating nested children, always exclude children marked for destruction
When your model is using a callback like before_save
or before_validation
to calculate an aggregated value from its children, it needs to skip those children that are #marked_for_destruction?
. Otherwise you will include children that have been ticked for deletion in a nested form.
Wrong way
class Invoice < ApplicationRecord
has_many :invoice_items
accepts_nested_attributes_for :invoice_items, :allow_destroy => true # the critical code 1/2
before_save :calculate_and_store_amount # the crit...
will_paginate on complex scopes may be slow (workaround)
will_paginate
triggers a database query to determine the total number of entries (i.e. to let you display the number of search results). When you paginate complex scope (e.g. that has many include
s), this query may take several seconds to complete.
If you encounter this behavior, a solution is to calculate the total count yourself and pass it to the pagination call:
scope = User.complex_scope_full_of_includes
total_number_of_users = scope.count
@users = scope.paginate(:total_entr...
In MySQL, a zero number equals any string
In MySQL comparing zero to a string 0 = "any string"
is always true!
So when you want to compare a string with a value of an integer column, you have to cast your integer value into a string like follows:
SELECT * from posts WHERE CAST(posts.comments_count AS CHAR) = '200'
Of course this is usually not what you want to use for selecting your data as this might cause some expensive database operations. No indexes can be used and a full table scan will always be triggered.
If possible, cast the compared value in your application to...
Find an ActiveRecord by any column (useful for Cucumber steps)
The attached patch lets you find a record by a string or number in any column:
User.find_by_anything('carla')
User.find_by_anything('email@domain.de')
User.find_by_anything(10023)
There's also a bang variant that raises ActiveRecord::NotFound
if no record matches the given value:
User.find_by_anything!('carla')
Boolean and binary columns are excluded from the search because that would be crazy.
I recommend copying the attachment to features/support/find_by_anything.rb
, since it is most useful in Cucumber step def...
High-level Javascript frameworks: Backbone vs. Ember vs. Knockout
This is a very general introduction to MV* Javascript frameworks. This card won't tell you anything new if you are already familiar with the products mentioned in the title.
As web applications move farther into the client, Javascript frameworks have sprung up that operate on a higher level of abstraction than DOM manipulation frameworks like jQuery and Prototype. Such high-level frameworks typically offer support for client-side view rendering, routing, data bindings, etc. This is useful, and when you write a moderately complex Javascript ...
How to overwrite and reset constants within Cucumber features
In order to save the original value of a constant, set the new value and restore the old value after a scenario was completed, you can use the following helper. It takes care of saving the old constant value, setting the new one without throwing warnings and resets the value with an After
hook.
This module also enables you to introduce new global constants.
Since these newly defined constants do not have any value to be reset to,
they simply are deleted (remove_const
) once the respective Cucumber step finishes.
You can copy the file at...
Fixing Graticule's "distance" for edge cases
Ever seen this error when using Graticule?
Numerical argument out of domain - acos
Similarly to the to_sql
problem for some edge cases, Graticule::Distance::Spherical.distance
(and possibly those of Graticule's other distance computation classes) is subject to Float
rounding errors.
This can cause the above error, when the arc cosine of something slightly more than 1.0 is to be computed, e.g. for the (zero) distance b...
Mysql::Error: SAVEPOINT active_record_1 does not exist: ROLLBACK TO SAVEPOINT active_record_1 (ActiveRecord::StatementInvalid)
Possible Reason 1: parallel_tests - running more processes than features
If you run old versions of parallel_tests with more processes than you have Cucumber features, you will get errors like this in unexpected places:
This is a bug caused by multiple processes running the same features on the same database.
The bug is fixed in versions 0.6.18+.
Possib...
Sunspot for Solr fails with '400 Bad Request' in 'adapt_response'
If Sunspot does not work and fails with a backtrace similar to this:
/project/shared/bundle/ruby/1.8/gems/rsolr-1.0.6/lib/rsolr/client.rb:227:in `adapt_response'
/project/shared/bundle/ruby/1.8/gems/rsolr-1.0.6/lib/rsolr/client.rb:164:in `execute'
/project/shared/bundle/ruby/1.8/gems/rsolr-1.0.6/lib/rsolr/client.rb:158:in `send_and_receive'
(eval):2:in `post'
then the schema.xml
that is shipped with Sunspot is not loaded into Solr correctly.
Often the latter can be found in /etc/solr/conf/schema.xml
. So copy Sunspo...
Why your javascripts should be executed after the dom has been loaded
Most of the JavaScript snippets have code that manipulates the DOM. For that reason dom manipulating javascript code should have been executed after the DOM has loaded completely. That means when the browser has finished HTML parsing and built the DOM tree. At that time, you can manipualte the DOM although not all resources (like images) are fully loaded.
The following snippets show how you can do this with plain JavaScript, jquery or prototype ([dom ready ...
Using Solr with Sunspot
This describes all the steps you'll need to get Solr up and running for your project using the Sunspot gem.
Prepare Sunspot on your development machine
What you want in your Gemfile:
gem 'sunspot_rails'
gem 'sunspot_solr'
gem 'progress_bar' # for sunspot:solr:reindex
Now define what should be indexed within Solr from your ActiveRecord models, e.g.,
class Article << ActiveRecord::Base
searchable do
text :title
...
gammons/fake_arel - GitHub
Gem to get Rails 3's new ActiveRecord query interface (where
, order
) and the new scope syntax (chaining scope definitions) in Rails 2.
You also get #to_sql
for scopes.