2013-06-24 93 views
2

我想通過JSON POST在rails服務器上創建'image'對象。這工作完美,但現在我添加了用戶身份驗證,它不再工作。 我使用gem'devise'進行身份驗證。 註冊,登錄和註銷與json完美協同工作。rails:使用json和用戶身份驗證創建新對象

user.rb:

class User < ActiveRecord::Base 
    has_many :images 

    attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :encrypted_password 

    has_secure_password 

    validates :email, format: /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, uniqueness: true 

end 

images_controller:

class ImagesController < ApplicationController 

before_filter :require_login #checks if user is logged in before user accesses images 

    respond_to :json 

def index 
    @images = current_user.images 

    respond_to do |format| 
     format.html { } 
     format.json { render :json => {:success => true, 
         :info => "images", 
         :data => @images } } 
    end 

    end 

    def edit 
    @image = current_user.images.find(params[:id]) 
    end 

    def new 
    @image = current_user.images.build 
    end 


    def create 
    @image = current_user.images.build(params[:image]) 

    respond_to do |format| 
     if @image.save 
     format.html { redirect_to images_path } 
     format.json { render :json => @image } 
     else 
     format.html { render "new" } 
     format.json { render json: @image.errors, status: :unprocessable_entity } 
     end 
    end #respond_to 
    end 

private 

    def require_login 
    unless user_signed_in? #in application_controller 
     redirect_to login_path, 
     alert: "Login first." 
    end 
    end 

    end 

sessions_controller:

class SessionsController < ApplicationController 

    respond_to :json 

    def new 
    #empty because no underlying model 
    end 


    def create 
    #user = User.find_by_email(params[:user][:email]) #when JSON: { "user" : { "email":"[email protected]", "password":"asdf" }} 
    user = User.find_by_email(params[:email]) #when JSON: { "email":"[email protected]", "password":"asdf" } 

    respond_to do |format| 
     if user && user.authenticate(params[:password]) #because user has_secure_password 
     session[:user_id] = user.id 

     format.html { redirect_to images_path, notice: "Login successful!" } 
     format.json { render :json => {:success => true, 
         :info => "Logged in", 
         :data => { } } } 
     else 
     format.html { flash.now.alert = "Wrong email or password" 
        render "new" } 
     format.json { render :json => {:success => false, :info => "Wrong email or password" } } 
     end 
    end 
    end 



    def destroy 

    session[:user_id] = nil 
    respond_to do |format| 
     format.html { redirect_to root_path, notice: "Logout successful!" } 
     format.json { render :json => {:success => true, 
         :info => "Logged out", 
         :data => { } } } 
    end 

    end 


end 

耙路線:

 root  /      pages#home 
new_image GET /images/new(.:format)  images#new 
    images GET /images(.:format)   images#index 
    image GET /images/:id(.:format)  images#show 
      POST /images(.:format)   images#create 
edit_image GET /images/:id/edit(.:format) images#edit 
      PUT /images/:id(.:format)  images#update 
    image DELETE /images/:id(.:format)  images#destroy 
    users POST /users(.:format)   users#create 
    new_user GET /users/new(.:format)  users#new 
    login GET /login(.:format)   sessions#new 
    sessions POST /sessions(.:format)  sessions#create 
    logout DELETE /logout(.:format)   sessions#destroy 

application_controller:

class ApplicationController < ActionController::Base 
    protect_from_forgery 

    def current_user 
    if session[:user_id] 
     @current_user ||= User.find(session[:user_id]) 
    end 
    end 

    def user_signed_in? 
    current_user.present? 
    end 

    helper_method :user_signed_in? 

end 

登錄後,其工作方式(顯示的圖像也可以與GET method and url http://localhost:3000/images),我無法與JSON的新形象。這是從客戶端我的要求(我使用Chrome的簡單的REST客戶端):

url:   http://localhost:3000/images 
method:  POST 
Content-Type: application/json 
       Accept: application/json 
Data:   {"image":{ "title":"someTitle","url": "someUrl" }} 

響應:

500 Internal Server Error 
<h1>Template is missing</h1> 
<p>Missing template sessions/new, application/new with {:locale=&gt;[:en], :formats=&gt;[:json], :handlers=&gt;[:erb, :builder, :coffee]}. Searched in: 
    * &quot;c:/Users/XXX/workspaceRubyOnRails/my_server/app/views&quot; 
    * &quot;c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/devise-2.2.4/app/views&quot; 
</p> 

回答

1

似乎您的JSON請求未經過身份驗證。因此,Devise會將您發送到登錄頁面。但是,您沒有登錄頁面的JSON版本,因此您會收到Missing template sessions/new錯誤。

您可以請求甚至更好的與令牌發送您的餅乾一起,使用token authentication從設計,所以你可以做你的要求進行認證這樣的:

curl -v -H "Accept: application/json" -H "Content-type: application/json" http://localhost:3000/images?auth_token=<token> 

你可以在這裏找到一些代碼示例: https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example

+0

我需要添加列「authentication_token」給用戶,對吧? –

+0

@AndiR。是的,你需要'authentication_token'列。 – htanata

+0

我同意。爲了維護會話,您必須在每個請求的頭部發送cookie。我建議在瀏覽器中使用由單個頁面應用程序使用的API的基於cookie的身份驗證,並且爲第三方使用的API使用omniauth。 – user1158559

0

我認爲你需要通過Chrome簡單的REST客戶端進行身份驗證 - 您的Rails應用程序似乎區分Chrome本身和其他客戶端。

我將擴大這個答案,一旦你已經超過了這個障礙。

+0

好吧,身份驗證似乎是從簡單的REST客戶端,因爲我可以登錄到服務器,然後查看特定用戶的圖像,所以GET工作。 –

+0

「require_login」包含什麼? –

+0

我編輯了我原來的帖子。 「require_login」表示僅當用戶登錄時纔可以訪問圖像(以防止使用「隨機」用戶標識進行外部訪問)。 –