What happens
When the user views a form to create, update, or destroy a resource, the Rails app creates a random authenticity_token
, stores this token in the session, and places it in a hidden field in the form. When the user submits the form, Rails looks for the authenticity_token
, compares it to the one stored in the session, and if they match the request is allowed to continue.
Why it happens
Since the authenticity token is stored in the session, the client cannot know its value. This prevents people from submitting forms to a Rails app without viewing the form within that app itself.
Imagine that you are using service A, you logged into the service and everything is ok. Now imagine that you went to use service B, and you saw a picture you like, and pressed on the picture to view a larger size of it. Now, if some evil code was there at service B, it might send a request to service A (which you are logged into), and ask to delete your account, by sending a request to http://serviceA.com/close_account
. This is what is known as CSRF (Cross Site Request Forgery).
If service A is using authenticity tokens, this attack vector is no longer applicable, since the request from service B would not contain the correct authenticity token, and will not be allowed to continue.
API docs describes details about meta tag:
CSRF protection is turned on with the protect_from_forgery
method,
which checks the token and resets the session if it doesn't match what
was expected. A call to this method is generated for new Rails
applications by default.
The token parameter is named authenticity_token
by default. The name
and value of this token must be added to every layout that renders
forms by including csrf_meta_tags
in the HTML head.
Notes
Keep in mind, Rails only verifies not idempotent methods (POST, PUT/PATCH and DELETE). GET request are not checked for authenticity token. Why? because the HTTP specification states that GET requests is idempotent and should not create, alter, or destroy resources at the server, and the request should be idempotent (if you run the same command multiple times, you should get the same result every time).
Also the real implementation is a bit more complicated as defined in the beginning, ensuring better security. Rails does not issue the same stored token with every form. Neither does it generate and store a different token every time. It generates and stores a cryptographic hash in a session and issues new cryptographic tokens, which can be matched against the stored one, every time a page is rendered. See request_forgery_protection.rb.
Lessons
Use authenticity_token
to protect your not idempotent methods (POST, PUT/PATCH, and DELETE). Also make sure not to allow any GET requests that could potentially modify resources on the server.
EDIT: Check the comment by @erturne regarding GET requests being idempotent. He explains it in a better way than I have done here.
The short answer for old versions of Rails (see other answers for Rails 4+):
add_index :table_name, :column_name, unique: true
To index multiple columns together, you pass an array of column names instead of a single column name,
add_index :table_name, [:column_name_a, :column_name_b], unique: true
If you get "index name... is too long", you can add name: "whatever"
to the add_index method to make the name shorter.
For fine-grained control, there's a "execute
" method that executes straight SQL.
That's it!
If you are doing this as a replacement for regular old model validations, check to see how it works. The error reporting to the user will likely not be as nice without model-level validations. You can always do both.
Best Answer
Guidelines built from personal experience:
serial primary key
in postgreSQL). Its use is somewhat complicated and not recommended.validates_uniqueness_of
andadd_index
with the:unique => true
option) instead to simulate primary key functionality on one of your own fields.These are the types about which confusion often exists; I hope this helps. I really don't know why there isn't official documentation about these. Also, I imagine these database adapters you referred to were written by the same people who wrote Rails, so they probably didn't need any documentation to go by when they were writing the adapters. Hope this helps!
Note: the presence of both
:DateTime
and:Timestamp
, from what I can find, is included by Rails mostly for compatibility with database systems. For instance, MySQL'sTIMESTAMP
datatype is stored as a unix timestamp. Its valid range goes from 1970 to 2038, and the time is stored as the number of seconds that have elapsed since the last epoch, which is supposedly standard, but in practice can differ from system to system. MySQL later introduced theDATETIME
datatype, which is stored as seconds (with optional fractional seconds as of 5.6.4) since "1000-01-01 00:00:00", at the cost of a size increase. TheTIMESTAMP
datatype was retained for backwards compatibility. Other database systems went through similar evolutions. Rails recognized that multiple standards existed, and provided interfaces to both. However, Rails ActiveRecord defaults both:Timestamp
and:DateTime
to UTC dates stored in MySql'sDATETIME
, so it makes no functional difference to Rails programmers. These exist so that users who wish to differentiate between the two can do so. (For a more in-depth explanation, see this SO answer).