我正在使用Rails 4构建一个简单的API,但是使用我的“创建”方法,这一切都非常糟糕。
以下是我的路线档案的相关部分:
namespace :api, defaults: { format: 'json' } do
# /api/... Api::
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :users
end
end
这是api / v1 / users_controller.rb:
class Api::V1::UsersController < ApplicationController
protect_from_forgery except: :create
respond_to :json
def index
respond_to do |format|
format.html {render text: "Your data was sucessfully loaded. Thanks"}
format.json { render text: User.last.to_json }
end
end
def show
respond_with User.find(params[:id])
end
def create
respond_with User.create(user_params)
end
def update
respond_with User.update(params[:id], params[:users])
end
def destroy
respond_with User.destroy(params[:id])
end
private
def user_params
params.require(:user).permit(:name, :age, :location, :genre_ids => [], :instrument_ids => [])
end
end
每当我尝试添加带有JSON的API时,我都会收到“{”错误“:{”name“:[”不能为空“]}}”
它可以用我的常规控制器创建一个用户,但我感觉我的API控制器由于强参数而搞砸了。
有关如何在Rails 4中正确执行此操作的任何建议? 此外,我通过我的用户模型有一些Has-Many-Through关系。 API的用户控制器应该可以看到蝙蝠,对吗?
由于
修改
我现在收到此错误:
修改
{
"name": "Sally",
"age": "23",
"location": "Blue York",
"genre_ids": [1, 2, 3]
}
再次编辑
即使在我的JSON调用中添加User参数,它仍然会给我带来相同的错误:user param missing。我是否错误地使用了强参数?在我的“常规”users_controller中,我可以使用我已设置的表单轻松创建用户,但是使用此API控制器,我似乎无法使用JSON创建一个。还有其他建议吗?
再次编辑 这是从开始到错误的日志
rails s
=> Booting WEBrick
=> Rails 4.0.1 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2013-12-19 14:03:01] INFO WEBrick 1.3.1
[2013-12-19 14:03:01] INFO ruby 1.9.3 (2013-02-22) [x86_64-darwin10.8.0]
[2013-12-19 14:03:01] INFO WEBrick::HTTPServer#start: pid=53778 port=3000
Started GET "/api/users" for 127.0.0.1 at 2013-12-19 14:03:02 -0500
ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by Api::V1::UsersController#index as JSON
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
Rendered text template (0.0ms)
Completed 200 OK in 142ms (Views: 27.8ms | ActiveRecord: 0.6ms)
[2013-12-19 14:03:03] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-12-19 14:03:03] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
Started POST "/api/users" for 127.0.0.1 at 2013-12-19 14:03:37 -0500
Processing by Api::V1::UsersController#create as JSON
Completed 400 Bad Request in 1ms
ActionController::ParameterMissing (param not found: user):
app/controllers/api/v1/users_controller.rb:40:in `user_params'
app/controllers/api/v1/users_controller.rb:20:in `create'
Rendered /usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack- 4.0.1/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.7ms)
Rendered /usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack-4.0.1/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
Rendered /usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack-4.0.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.8ms)
Rendered /usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack- 4.0.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (31.6ms)
编辑#6 这是我的“真正的”users_controller,它位于我的应用程序而不是我的API中。表单从此控制器创建用户,而不是API控制器。
class UsersController < ApplicationController
def index
@users = User.all
@genres = Genre.all
@instruments = Instrument.all
render json: @users
end
def new
@user = User.new
end
def show
@user = User.find(params[:id])
end
def create
@user = User.new(user_params)
if @user.save
render json: @user, status: :created, location: @user
else
render json: @user.errors, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name, :age, :location, :genre_ids => [], :instrument_ids => [])
end
end
另外 - 用户表单
<div class="row">
<div class="span6 offset3">
<%= form_for(@user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :age %>
<%= f.text_field :age %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :location %>
<%= f.text_field :location %>
<br>
<% Genre.all.each do |genre| %>
<%= check_box_tag "user[genre_ids][]", genre.id %>
<%= genre.name %><br>
<% end %>
<br>
<% Instrument.all.each do |instrument| %>
<%= check_box_tag "user[instrument_ids][]", instrument.id %>
<%= instrument.name %><br>
<% end %>
<%= f.submit "Create My Account!" %>
<% end %>
</div>
</div>
<%= users_path %>
这是我的user.rb文件
class User < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 50 }
has_many :generalizations
has_many :genres, through: :generalizations
has_many :instrumentations
has_many :instruments, through: :instrumentations
end
以下是我在路线档案中的内容:
namespace :api do
namespace :v1 do
resources :users
end
end
我的POST请求
POST / api / v1 / users HTTP / 1.1 主持人:localhost:3000 缓存控制:无缓存
{“user”:{“name”:“Sally”,“age”:“23”,“location”:“Blue York”,“genre_ids”:[1,2,3]}}
更新
我改变了我的强力范围:
def user_params
params.require(:user).permit(:name, :age, :location, :genre_ids => [], :instrument_ids => []) if params[:user]
end
所以最后的“if”语句会使错误消失,但每当我发布到我的API时,它都会返回“null”。所以这可能与以前一样,但以不同的方式显示。但是,与此同时,它可能是进步!
以下是上次更新的日志
Started POST "/api/v1/users" for 127.0.0.1 at 2013-12-21 11:38:03 -0500
Processing by API::V1::UsersController#create as */*
(0.1ms) begin transaction
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
(0.1ms) rollback transaction
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
Rendered text template (0.0ms)
Completed 200 OK in 20ms (Views: 0.3ms | ActiveRecord: 0.6ms)
最终更新 我错过了一些东西,但最重要的是我错过了“Content-Type - application / json”作为我的标题。 我觉得很有成就感!感谢大家的帮助!
答案 0 :(得分:4)
Rails 4是构建API的绝佳选择。我会选择rails-api gem。它将比完整的Rails堆栈更好地执行。
我使用Rails API gem在Rails中构建了大量API。通常与RABL结合使用(您可以使用它创建漂亮的模板来呈现JSON)。我不是将API直接集成到您的生产Rails应用程序(提供网站和JSON)的忠实粉丝,因为随着时间的推移,当您开始向API添加更多版本时,您会产生很大的混乱。有一些非常好的Railscasts(www.railscasts.com):搜索API。
访问API时,您将在application_controller.rb文件中使用全局过滤器。你可以这样做:
before_filter :authenticate_user, :except => 'users#index'
private
def authenticate_user
@current_user = User.find_by_api_key(params[:token])
unless @current_user
render :status=>403, :json=>{:message=>"Invalid token"}
end
end
def current_user
@current_user
end
end
在这种情况下,您将在请求中发送令牌(快速而脏,而不是使用标头)作为请求参数。您需要将API密钥或您想要使用的任何内容添加到用户模型中。只需创建一个添加api_key的迁移,或者你想要将其调用到用户模型,或者创建一个包含密钥,机密等的新表以及belongs_to的user_id字段(以及用户has_many api_keys或has_one)。这样,您可以随时允许用户更改其密钥等(重新生成),而不会弄乱用户名/密码,甚至允许他们使用多个API密钥和一些标签(测试,生产等)。对于您的用户注册,您可以添加到您的模型中:
before_create :generate_api_key
然后创建一个简单的方法,如:
def generate_api_key
begin
self.api_key = SecureRandom.hex
end while self.class.exists?(api_key: api_key)
end
希望它有所帮助!
答案 1 :(得分:3)
根据您发布的JSON中的代码参数,应该在params[:user]
内。所以JSON应该是这样的:
{
"user": {
"name": "Sally",
"age": "23",
"location": "Blue York",
"genre_ids": [1, 2, 3]
}
}