6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Railsで、どんなモデルに対してもメモを取れるようにする

Last updated at Posted at 2013-10-30

今回は営業の人が顧客だったり、商品だったり、会社だったりのモデルに対して共有できるメモを取るというニーズを想定し、SalesNoteというモデル名を使うことにする。

モデル生成

どのモデルにでも紐付けられるようにPolymorphic Associationで作る。

bash
rails g model SalesNote target_id:integer target_type:string content:text

して、生成したMigrationファイルにインデックスを張る命令だけ付け加える。

add_index :sales_notes, [:target_id, :target_type]

結果、以下のMigrationファイルが出来上がる。

db/migrate/201301234543_create_sales_notes.rb
class CreateSalesNotes < ActiveRecord::Migration
  def change
    create_table :sales_notes do |t|
      t.integer :target_id
      t.string :target_type
      t.text :content

      t.timestamps
    end
    add_index :sales_notes, [:target_id, :target_type]
  end
end

モデル

モデルは自動で生成されるはずだが、ここではvalidationだけ軽くつけておくことにする。

class SalesNote < ActiveRecord::Base
  belongs_to :target, polymorphic: true, inverse_of: :notes
  attr_accessible :content
  validates_presence_of :target_id, :target_type
end

Noteをつける側のモデル

app/models/concerns/sales_note_takable_concern.rb
module SalesNoteTakableConcern
  extend ActiveSupport::Concern
  included do
    has_one :sales_note, as: :target, inverse_of: :target
  end
end

を作って、

app/models/user.rb
class User
  include SalesNoteTakableConcern
end

というように使う。

ルート

config/routes.rb
namespace :admin do
  resources :sales_notes, only: [:create, :update]
end

コントローラー

app/cntrollers/admin/sales_notes_controller.rb
class Admin::SalesNotesController < Admin::BaseController
  before_filter :find_note  # before_action

  def create
    create_or_update
  end

  def update
    create_or_update
  end

  private
  def find_note
    @sales_note = SalesNote.where(target_id: params[:sales_note][:target_id], target_type: params[:sales_note][:target_type]).first_or_initialize
  end

  def create_or_update
    params[:sales_note].delete(:target_id)
    params[:sales_note].delete(:target_type)
    respond_to do |format|
      if @sales_note.update_attributes(params[:sales_note])
        format.html { redirect_to :back, notice: "ノートが更新されました" }
        format.js { head :ok }
      else
        format.html { redirect_to :back, alert: "ノートの更新に失敗しました" }
        format.js { head :not_acceptable }  # 406
      end
    end
  end
end

ビュー

一般ユーザーには見えないようにAdmin用のViewで行う。
Admin::BaseControllerにUserがAdminかの判定がある想定。

app/views/admin/base/_sales_note_form.html.haml
.sales_memo
  %h3 メモ
  - sales_note = target_model.sales_note || target_model.build_sales_note
  = form_for [:admin, sales_note], remote: true, html: { id: "sales_note_form" } do |f|
    = f.hidden_field :target_id
    = f.hidden_field :target_type
    = f.text_area :content, style: "height: 60px; width: 290px;"
    = f.submit 'save', id: 'sales_note_save', class: "btn blue", style: "width: 100px; height: 30px; padding: 0", disabled: :disabled
    %span#sales_note_save_notification{ style: "margin: 0 10px; font-size: 20px; display: hidden; color: red;"} saved!

:javascript
  var memoContent = $('#sales_note_content').val();
  $('#sales_note_content').on('input propertychange', function() {
    if ($(this).val() == memoContent) $('#sales_note_save').attr('disabled', 'disabled');
    else $('#sales_note_save').attr('disabled', null);
  });
  $('#sales_note_form').on('ajax:success', function(event, data, status, xhr) {
    memoContent = $('#sales_note_content').val();
    $('#sales_note_save').attr('disabled', 'disabled');
    $('#sales_note_save_notification').show('slow').delay(1000).hide('fast');
  });
  
  $(function(){
    $('#sales_note_content').autosize();
  });

とPartialViewを作っておいて、

app/views/admin/user/show.html.haml
= render 'sales_note_form', target_model: @user

app/views/user/show.html.haml
= render 'admin/base/sales_note_form', target_model: @user if current_user.admin?

の用に使う。

Javascriptの部分は、メモが編集されている時のみ、ボタンがEnableされて保存することができるようにしているコードが大半。ココらへんは最悪必要ないし、適当でいいと思う。
テキストは適宜大きくなるように、jqueryのautosizeをつけている。(http://www.jacklmoore.com/autosize/)
autosizeはもともと有名だったAutoResizeがメンテされなくなって使われるようになった。AutoResizeよりちょっと英語が変だけど気にしない。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?