When I use link_to :method=>:delete, what rails has generated is a javascript click, which is not nice if you do come across situation your client just have javascript disabled. That seems a bad idea to me. Any chance to get around this?
Javascript – Rails active_resource require JS to do delete by link_to
activeresourcejavascriptrubyruby-on-rails
Related Solutions
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 namedauthenticity_token
by default. The name and value of this token must be added to every layout that renders forms by includingcsrf_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.
rename_column :table, :old_column, :new_column
You'll probably want to create a separate migration to do this. (Rename FixColumnName
as you will.):
script/generate migration FixColumnName
# creates db/migrate/xxxxxxxxxx_fix_column_name.rb
Then edit the migration to do your will:
# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
def self.up
rename_column :table_name, :old_column, :new_column
end
def self.down
# rename back if you need or do something else or do nothing
end
end
For Rails 3.1 use:
While, the up
and down
methods still apply, Rails 3.1 receives a change
method that "knows how to migrate your database and reverse it when the migration is rolled back without the need to write a separate down method".
See "Active Record Migrations" for more information.
rails g migration FixColumnName
class FixColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
If you happen to have a whole bunch of columns to rename, or something that would have required repeating the table name over and over again:
rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...
You could use change_table
to keep things a little neater:
class FixColumnNames < ActiveRecord::Migration
def change
change_table :table_name do |t|
t.rename :old_column1, :new_column1
t.rename :old_column2, :new_column2
...
end
end
end
Then just db:migrate
as usual or however you go about your business.
For Rails 4:
While creating a Migration
for renaming a column, Rails 4 generates a change
method instead of up
and down
as mentioned in the above section. The generated change
method is:
$ > rails g migration ChangeColumnName
which will create a migration file similar to:
class ChangeColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end
end
Related Question
- Ruby-on-rails – How to get the current absolute URL in Ruby on Rails
- Javascript – How to decide when to use Node.js
- Javascript – Using Rails 3.1, where do you put your “page specific” JavaScript code
- Javascript – Should CSS always preceed Javascript
- Ruby-on-rails – Rails 4 Authenticity Token
- Javascript – Rails 4: how to use $(document).ready() with turbo-links
- Javascript – Using Node.js require vs. ES6 import/export
Best Solution
What it generates is a form with method="delete", your best bet is to make the form yourself, the only thing is that the submit button won't be a link, but a button.
You should not, by any mean, try to do it with a basic
<a href="">
, because a disruptive action (create, update, delete) should not be made with aGET
request.