我一直遇到将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的原因,因为我想它会使原始请求比必要的更加混乱。
答案 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