【发布时间】:2015-07-18 20:35:18
【问题描述】:
我在向我的 Rails 4.0 应用程序发布 JSON 请求以进行登录时遇到问题。我设置了一个非常小的登录-注销会话控制器,以便了解 Rails 如何接受JSON 请求,而不是摆弄像 devise 这样更丰富的库。在客户端和服务器端经过数小时的混淆以及混合和匹配方法之后,我相信问题在于我对 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 的原因,因为我认为它会使原始请求变得比必要的更混乱。
【问题讨论】:
-
如果请求包含标头
Content-Type: application/json,则应自动为您解析参数。查看发出请求的前端代码(任何 HTML 和 JavaScript)可能很有用。 -
看来你的参数是字符串。如何创建请求?
-
james246:我没有任何 HTML 或 JS 的请求,虽然我已经添加了要使用浏览器提交的表单的视图代码,现在我已经包含在我的原始帖子以及用于构建和发布请求的 Objective C。
-
BroiSatse:我通过在刚刚添加的表单上发布或通过 Objective C 生成的 JSON 请求来创建它。
-
您的 objectve C 代码在这里出错。看看这个问题来解决它:stackoverflow.com/questions/16698387/…
标签: ruby-on-rails ruby json ruby-on-rails-4