【问题标题】:Rails 4 API with Strong Parameters?具有强参数的 Rails 4 API?
【发布时间】:2014-01-07 04:16:08
【问题描述】:

我正在使用 Rails 4 构建一个简单的 API,但是使用我的“create”方法,这一切都变得非常糟糕。

这是我的路线文件的相关部分:

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 时,我都会收到 "{"errors":{"name":["can't be blank"]}}"

它可以使用我的常规控制器创建用户,但我感觉我的 API 控制器因为强参数而变得一团糟。

关于如何在 Rails 4 中正确执行此操作的任何建议? 此外,通过我的用户模型,我有一些 Has-Many-Through 关系。 API 的用户控制器应该能够立即看到这一点,对吧?

谢谢

编辑:

我现在收到此错误:

编辑:

{
  "name": "Sally",
  "age": "23",
  "location": "Blue York",
  "genre_ids": [1, 2, 3]
}

再次编辑

即使在我的 JSON 调用中添加了 User 参数,它仍然给我同样的错误 :user 参数丢失。我是否错误地使用了强参数?在我的“常规”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 这是我的“真实”用户控制器,它存在于我的应用程序中,而不是我的 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

ALSO - 用户表单

<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 主机:本地主机: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”作为我的标题。 我觉得很有成就感!谢谢大家的帮助!

【问题讨论】:

  • 你是如何调用你的 API 的?
  • 您好,感谢您的回复。我将在我的 OP 中更新以获得更好的格式。
  • 我想我正在使用一个名为 Postman 的 Chrome 扩展程序,它可以让您进行 JSON 或纯文本调用。我正在向localhost:3000/api/users发出 POST 电话
  • 您能否添加从 Started ... 到 Completed 的日志输出?
  • @eightonrose 我已经设置并且一切正常。你可以发布你的路线吗?我是resources :users。

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


【解决方案1】:

根据您发布的 JSON 中的代码参数,您应该在 params[:user] 内。所以 JSON 应该是这样的:

{
  "user": {
    "name": "Sally",
    "age": "23",
    "location": "Blue York",
    "genre_ids": [1, 2, 3]
  }
}

【讨论】:

  • 嘿,很好的建议,谢谢,但我仍然遇到同样的错误。 :( 还有其他建议吗?
  • 我复制并粘贴了您所拥有的内容并重新启动了我的服务器。有没有可能因为某种原因看不到我的模型中的内容?
【解决方案2】:

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

希望对你有帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    相关资源
    最近更新 更多