0

I'm new to angularJS and Rails,and I tried to building a Rails application with AngularJS

and now, I want to do a POST request to sent data insert database

Activity Controller

def create
        @activity = Activity.new(params[:activity])

        respond_to do |format|
            if @activity.save
                format.html {redirect_to activities_url}
                format.json { render activities_url, status: :created, location: @activity}
            end
        end

end

Activity Coffee JS

app = module('activity', ['ngAnimate'])
app.controller 'FormCtrl', ($scope, $http) ->
    config = {
        header: {
            'Content-Type': 'application/json'
        }
    }
    @test = ->
        $http.post('/activities.json', {title: 'test1'}, config).success (data, status) ->
            console.log(data)
            console.log(status)
return

Console log

Started POST "/activities.json" for ::1 at 2016-05-04 21:06:10 +0800
Processing by ActivitiesController#create as JSON
  Parameters: {"title"=>"test1", "activity"=>{"title"=>"test1"}}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 2ms (ActiveRecord: 0.0ms)

I created a button of ng-click to trigger test function but I got information like console log, How can I do to fix it?

Champer Wu
  • 1,101
  • 3
  • 13
  • 32
  • Possible duplicate of [Rails API design without disabling CSRF protection](http://stackoverflow.com/questions/7600347/rails-api-design-without-disabling-csrf-protection) – chad_ May 04 '16 at 13:22

3 Answers3

2

There is a great answer here: Rails API design without disabling CSRF protection

The gist of it is that you can put the CSRF token in a cookie called XSRF-TOKEN like so:

# In my ApplicationController
after_filter :set_csrf_cookie

def set_csrf_cookie
  if protect_against_forgery?
    cookies['XSRF-TOKEN'] = form_authenticity_token
  end
end

You'll then have to overload the verified_request? method in your ApplicationController to load the token from where Angular will return it:

protected

def verified_request?
  super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
end

(read the link I included though.. there are caveats, but I think you want something like this anyway... basically your login actions shouldn't be protected against csrf, but other potentially destructive actions should. You could achieve this with skip_before_filter.)

I hope that helps!

chad_
  • 3,749
  • 2
  • 22
  • 22
  • Great answer, much better than mine. – Patrick Narkinsky May 04 '16 at 13:22
  • Thanks! No offense intended by my comment on your answer, I just cringe when I think of the potential issues w/ going without it. – chad_ May 04 '16 at 13:26
  • Thanks for answer. And now, I have new question, I success to sent data into database, but why I can't see the data update unless I refresh browser by myself ? – Champer Wu May 04 '16 at 13:47
  • 1
    That's a whole other thing. Basically you'd ideally build an AngularJS service (https://docs.angularjs.org/api/ng/service) to wrap your interactions with the Rails api you're building. Then the service will take responses from Rails and update your Angular scope. – chad_ May 04 '16 at 13:49
  • Are you seeing the ```data``` in your console? Your page would have to have some variable bound that you put ```data``` into. – chad_ May 04 '16 at 13:51
  • Yes, the console of data is success, but `http.get` in other controller can't show my new data unless I refresh brower – Champer Wu May 04 '16 at 13:56
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/111011/discussion-between-chad-and-champer-wu). – chad_ May 04 '16 at 14:03
1

I believe the quickest way of achieving this is with the helper method form_authenticity_token.

$http({
  method: 'POST',
  url: '<%= some_path %>',
  params: { 
    authenticity_token: '<%= form_authenticity_token %>',
    ... // Other params
  }
})

There is no need to disble CSRF which I don't recommend at all.

mariowise
  • 2,167
  • 2
  • 21
  • 34
0

Your issue is a feature of rails designed to defeat so-called "Cross Site Request Forgery". The Rails team has described this in some detail on their website, but basically it's a generated token that seeks to ensure that the form that generates a request to the web api is the form you provide. This often causes hassles with single page AJAX apps.

The 'quick fix' would be to disable CSRF by adding something like this to your Controller.

protect_from_forgery :except => :create

Hope this helps!

  • While it is a 'quick fix' in that it makes things happen and removes the current road block, I think csrf is worth a few minutes of up front work to avoid any trouble in the chance your site/app becomes popular enough to become a target. – chad_ May 04 '16 at 13:25
  • 1
    Don't disagree. CSRF is worth keeping around for production code. – Patrick Narkinsky Jul 19 '17 at 21:22