2013年11月15日金曜日

Railsでタグ機能を作成する。

タグ機能の実装を考えてみる。
モデル構成はこんな感じ。
UserとProjectがm:n
ProjectHistoryが中間テーブル。has_and_belongs_to_manyでもいいぐらいのテーブル
Userが複数のProjectというタグを持つイメージ
また、一つのタグは複数のユーザーにも共有される。
使用したjavascriptは
jquery.tagsinput.js
jquery-ui.js
オートコンプリート機能つきです。
ソースコードは、どうでもいいところは省略しています。

class User < ActiveRecord::Base
  has_many :project_histories
  has_many :projects, :through => :project_histories

  attr_accessor :project_tags
end
class ProjectHistory < ActiveRecord::Base
  attr_accessible :project_id, :user_id
  belongs_to :user
  belongs_to :project
end
class Project < ActiveRecord::Base
  attr_accessible :name
end
users_controllerの実装
def new
  @user = User.find(params[:id])
end

def create
  @user = User.new
  project_tags = params[:user].fetch("project_tags")
  params[:user].delete("project_tags")
  Project.transaction do
    tags = project_tags.split(",").uniq
    tags.each do |v|
      @user.projects << Project.new(name: v)
    end
  end

  respond_to do |format|
  
  end
end

def edit
  @user = User.find(params[:id])
  @user.project_tags = @user.projects.map(&:name).join(",")
end

def update
  @user = User.find(params[:id])
  project_tags = params[:user].fetch("project_tags")
  params[:user].delete("project_tags")
  Project.transaction do
    @user.projects.clear
    tags = project_tags.split(",").uniq
    tags.each do |v|
      pro = if Project.find_by_name(v)
        Project.find_by_name(v)
      else
        Project.new(name: v)
      end
        @user.projects << pro
    end
  end

  respond_to do |format|
    if @user.update_attributes(params[:user])
      format.html { redirect_to @user, notice: 'User was successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
    end
  end
end
API用のprojects_controllerの実装
def index
  @projects = Project.find(:all, :conditions => ["name LIKE ?", "%"+params[:term]+"%"])
  val = []
  @projects.each do |project|
    v = {}
    v[:value] = project.name
    val << v
  end
  respond_to do |format|
    format.json { render json: val }
  end
end
_form.html.erbの実装
<%= simple_form_for(@user) do |f| %>
  <%= f.input :project_tags %>
  
<%= f.submit(:class => "btn btn-primary") %>
<% end %>

0 件のコメント: