Rails 4.0应用程序的JSON POST请求提供响应代码500

时间:2015-07-18 20:35:19

标签: ruby-on-rails ruby json ruby-on-rails-4

我一直遇到将JSON请求发布到我的Rails 4.0应用程序以进行登录的问题。我设置了一个非常小的登录注销会话控制器,以便我可以理解Rails如何接受JSON请求,而不是摆弄更丰富的库,如设计。在客户端和服务器端经过数小时的混淆,混合和匹配方法之后,我认为问题在于我对Rails如何解析以字符串形式到达并可以通过Rails处理的JSON请求缺乏了解。用于登录和注销的会话控制器位于以下位置:

class SessionsController < ApplicationController
  respond_to do |format|
      format.html
      format.json {render json: params}
  end

  def new    
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      log_in user
      params[:session][:remember_me] == '1' ? remember(user) : forget(user)
      redirect_to user
    else
      flash.now[:danger] = 'Invalid email/password combination
      render 'new'
    end
  end

  def destroy
    log_out if logged_in?
    redirect_to root_url
  end
end

Rails上的活动在收到JSON请求时显示以下内容:

Started POST "/login/" for ::1 at 2015-07-17 21:47:49 +0000
Processing by SessionsController#create as JSON
  Parameters: {"{session:{email: 'user@example.com',password: 'aaaaaa', remember_me: 1}}"=>"[FILTERED]"}
Completed 500 Internal Server Error in 5ms (ActiveRecord: 0.0ms)

NoMethodError (undefined method `[]' for nil:NilClass):
  app/controllers/sessions_controller.rb:13:in `create'

我尝试了很多变体,只是在键和关键值周围加上引号,只在键周围加上引号,只有值,但最终,JSON请求将被选为具有这种未解析格式的字符串:“{session ......}“或”session:{...}“而不是像

这样的解析散列
"session"=>{"email"=>"user@example.com", "password"=>"[FILTERED]", "remember_me"=>"0"}

作为参考,我从浏览器成功登录时收到的消息显示如下:

Started POST "/login" for ::1 at 2015-07-18 13:28:45 +0000
Processing by SessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"AmuA2AJUYmnnexUUTCYsLhyNTxUI1t4sf7rbW9WcD7/Amt33DMAR8QHQM5U9RT0oEd0Y5jN564r7bpVf9PjxAg==", "session"=>{"email"=>"user@example.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"}
  User Load (16.5ms)  SELECT  "users".* FROM "users" WHERE "users"."email" = ? LIMIT 1  [["email", "user@example.com"]]
   (0.1ms)  begin transaction
   (0.1ms)  commit transaction
Redirected to http://localhost:3000/users/1
Completed 302 Found in 313ms (ActiveRecord: 17.4ms)

非常感谢任何帮助。

附录:

以下是登录视图的代码:

<% provide(:title, 'Login') %>
<h1>Log in</h1>
<div class='row'>
    <div class='col-md-6 col-md-offset-3'>
        <%= form_for(:session, url: login_path) do |f| %>

            <%= f.label :email %>
            <%= f.email_field :email, class:'form-control' %>

            <%= f.label :password %>
            <%= f.password_field :password, class:'form-control' %>

            <%= f.label :remember_me, class: 'checkbox inline' do%>
                <%= f.check_box :remember_me %>
                <span>Remember me on this computer</span>
            <%= f.text_area :buh, class:'form-control' %>
            <% end %>


            <%= f.submit 'Log in', class:'btn btn-primary'%>

            <p>New user? <%= link_to 'Sign up now!', signup_path %></p>
        <% end %>
    </div>
</div>

用于发布http请求的Objective C代码:

- (IBAction)loginPressed:(UIButton *)sender {
    NSInteger success = 0;

//payload below
    NSString *cookie = [self CSRFTokenFromURL:@"http://localhost:3000/login"];

    NSString *post = [[NSString alloc] initWithFormat:@"'session':{'email': '%@','password': '%@', 'remember_me': '1' }",username.text,password.text];
    NSLog(@"Postdata: %@",post);

    NSURL *url = [NSURL URLWithString: @"http://localhost:3000/login/"];

    NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];

    NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[post length]];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:url];
    [request setHTTPMethod: @"POST"];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    [request setValue:token forHTTPHeaderField:@"X-CSRF-Token"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:postData];

    NSError *error = [[NSError alloc] init];
    NSHTTPURLResponse *response = nil;
    NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

    NSLog(@"Response code: %ld", [response statusCode]);

    if ([response statusCode] >= 200 && [response statusCode] < 300) {
        NSString *responseData = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
        NSLog(@"Response ==> %@", responseData);

        NSError *error = nil;
        NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:urlData
                                                                 options:NSJSONReadingMutableContainers
                                                                   error:&error];
        success = [jsonData[@"success"] integerValue];
        NSLog(@"Success: %ld",(long)success);

        if (success == 1) {
            NSLog(@"Login SUCCESS");
        } else {
            NSString *error_msg = (NSString *) jsonData[@"error_message"];
            [self alertStatus:error_msg :@"Sign in Failed!" :0];
        }
    }
}

同样,我这样做是为了让自己了解Rails使用JSON httprequests的基本方法,而不是使用RESTKit,AFNetworking,Devise或其他各种库来处理创建登录会话在Objective C和Rails之间,这就是我保留Objective C的原因,因为我想它会使原始请求比必要的更加混乱。

1 个答案:

答案 0 :(得分:0)

如果你仔细观察你的参数,你会发现它们的格式不正确,我建议你用curl测试它:

curl -H "Content-Type: application/json" -X POST -d '"session":{"email":"user@example.com", "password":"yourpass", "remember_me":"0"}' http://localhost:3000/login