図書管理システム karitakke 製作その３


図書管理システムkaritakkeの製作記です。単なる備忘録です。
過去の投稿は以下から！

 - [システム概要](http://qiita.com/alice02/items/cb1412f77160fa354566)
 - [製作その１](http://qiita.com/alice02/items/16198c286d685f143754)
 - [製作その２](http://qiita.com/alice02/items/4ad0d55ca016a32fd252)

## Amazon APIをつかってISBNから本の情報を取得
こんな感じでISBNコードを入力して検索ボタンを押すと、
![01.png](https://qiita-image-store.s3.amazonaws.com/0/72278/6bcf755d-a6ec-04da-c347-20d9128da898.png "01.png")
書籍情報を取得できるようにします。
![02.png](https://qiita-image-store.s3.amazonaws.com/0/72278/a55493ed-dadd-5a8a-dbc4-644f7a368ac6.png "02.png")

### 下準備
Amazonで
 - アクセスキー
 - シークレットキー
 - アソシエイトタグ
を取得します。そして`config/application.rb`に以下を追記します。中身は取得したものに適宜変更してください。

``` ruby:config/application.rb
Amazon::Ecs.options = {
    :associate_tag =>     'アソシエイトタグ',
    :AWS_access_key_id => 'アクセスキー',
    :AWS_secret_key =>   'シークレットキー'
}
```

### ルーティングの変更
`config/routes.rb`に以下を追加します。

``` ruby:config/routes.rb
  get 'get_info', to: 'books#get_info', path: "/books/new/get_info"
```
/books/new/get_infoというURLはBooksコントローラーのget_infoというメソッドで処理するようにします。

### コントローラー
上でルーティングの設定をしたので、Booksコントローラーにget_infoメソッドを追加していきます。

``` ruby:app/controllers/books_controller.rb
  def get_info
    Amazon::Ecs.debug = true
    res = Amazon::Ecs.item_search(params[:isbn],
         :search_index   => 'Books',
         :response_group => 'Medium',
         :country        => 'jp'
       )
    info = {'Title' => res.first_item.get('ItemAttributes/Title'),
            'Author' => res.first_item.get('ItemAttributes/Author'),
            'Manufacturer' => res.first_item.get('ItemAttributes/Manufacturer'),
            'Publication_Date' => res.first_item.get('ItemAttributes/PublicationDate')
            }
    render json: info
  end
```
Amazon APIからISBNコードで書籍情報を取得し、タイトル・著者名・出版社・出版日をJSON形式で吐き出します。

### CoffeeScript
[こちら](http://qiita.com/inodev/items/9e08261c658c87cf777d)のページを参考に、

 - ISBNコードを数値のみ入力させる
 - Amazon APIにISBNコードを投げて帰ってきた書籍情報をフォームに入力するAjax処理

を作ります。

``` coffee:app/assets/javascripts/books.coffee
$(document).on 'ready page:load', -> # turbolinks対策
  ### ISBNコード入力フォーム：数値のみの入力 ###
  $('#book_isbn').keydown ->
    presskey = String.fromCharCode(event.keyCode);
    event.returnValue = /[0-9\b\t\n]/.test(presskey) # 入力受付キーを正規表現で指定

  ### 書籍情報取得ボタン：Ajaxで情報取得 ###
  $('#info_search_button').click ->
    isbncode = $('#book_isbn').val()
    $.ajax
      async:    true
      url:      "/books/new/get_info/"
      type:     "GET"
      data:     {isbn: isbncode}
      dataType: "json"
      context:  this
      error: (jqXHR, textStatus, errorThrown) -> # 通信/サーバエラーなど
        $("#msg").css("color","#ff0000").html(errorThrown)
      success:  (data, textStatus, jqXHR) ->
        if data?
          $("#book_title").val(data.Title) # タイトル
          $("#book_author").val(data.Author) # 著者
          $("#book_manufacturer").val(data.Manufacturer) # 出版社
          $("#book_publication_date").val(data.Publication_Date) # 出版日
        else
          $("#msg").css("color","#ff0000").html("書籍情報が見つかりませんでした。")

  ### MSGのリセット ###
  $("#book_isbn").change -> $("#msg").html("")

```


## cancancanを使ってみる！
[製作その１](http://qiita.com/alice02/items/16198c286d685f143754)でcancancanの設定をしてあるので、実際に使ってみましょう。
まず、`app/models/ability.rb`を以下のように編集します。管理者には全ての権限を与え、一般ユーザーはUserモデルの更新、Bookの閲覧、Rentalに関する全ての操作を許可し、ログを閲覧、削除できないようにします。

``` ruby:app/models/ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    if user.admin?
      can :manage, :all
    else
      can :update, User
      can :read, Book
      can :manage, Rental
      cannot :read, Log
      cannot :destroy, Log
    end
  end
end
```

次に該当するコントローラに以下を追加します。

```
load_and_authorize_resource
```

例えば、

``` ruby:app/controllers/books_controller.rb
class BooksController < ApplicationController

  load_and_authorize_resource
  before_action :set_book, only: [:show, :edit, :update, :destroy]

  def index
  	...
```
のようになります。
さらに、`app/controllers/apprication_controller.rb`を以下のようにします。

``` ruby:app/controllers/apprication_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  before_action :authenticate_user!

  before_action :configure_permitted_parameters, if: :devise_controller?

  # 以下を追加
  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_url, :alert => exception.message
  end

  protected
  
  def configure_permitted_parameters
   # 省略 ...
  end
end
```
設定はこんな感じでオッケーです。
あとはViewを編集します。たとえば、

```
<div class="btn-group">
    <%= link_to 'Show', book_path(b.id), class: "btn btn-info" %>
    <% if can? :update, Book %>
    <%= link_to 'Edit', edit_book_path(b.id), class: "btn btn-success" %>
    <% end %>
    <% if can? :destroy, Book %>
    <%= link_to 'Destroy', book_path(b.id), method: :delete, data: { confirm: "削除してもよろしいですか？" }, :class => "btn btn-danger" %>
	<% end %>
</div>
```
こんな感じにすると、権限を持っているユーザーにはEditボタン、Deleteボタンが表示されます。Showは全てのユーザーに表示されます。


## 完成？
これでとりあえずおわり。


## 参考
 - [Rails4/jQuery/JSONで郵便番号から住所を自動入力する具体的実装内容](http://qiita.com/inodev/items/9e08261c658c87cf777d)
 - [Cancanで管理者と一般ユーザを簡単にわける方法 - ユーザタイプごとの役割の設定（認可）](http://qiita.com/ShimojiK/items/2b5f8d1729cbc28b48c2)