#Создание дерева в таблице базы данных с помощью гема ANCESTRY https://github.com/stefankroes/ancestry
http://railscasts.com/episodes/262-trees-with-ancestry
Сначала добавляем gem 'ancestry' в Gemfile, затем делаем bundle install.
Теперь пишем в модели таблицы, которую хотим превратить в дерево has_acestry:
..\app\models\malfunctions.rb
class Malfunction < ActiveRecord::Base
has_ancestry
end
Теперь добавляем колонку acestry в таблице malfuctions базы данных и индексируем ее. Как это сделать, смотрим здесь: https://gist.github.com/elvisgiv/7688d3fd3c422d9ac8ca
Теперь мы должны создать экшен new, который будет рендерить соответствующую ему вьюху:
..\app\controllers\malfunctions_controller.rb
class MalfunctionsController < ApplicationController
...
def new
@id = params[:parent_id]
@malfunction = Malfunction.new
end
...
end
:parent_id дает нам гем. В нее из приходят данные из URL.
Делаем вьюху:
..\app\views\malfunctions\new.html.haml
%h1 New malfunction
= render 'form'
..\app\views\malfunctions\_form.html.haml
= simple_form_for @malfunction, :html => { :class => "form-horizontal", :role => "form" } do |f|
- if @malfunction.errors.any?
#form_errors.error
= f.error_notification
%h2
#{pluralize(@malfunction.errors.count, "error")}:
%ul
- @malfunction.errors.full_messages.each do |msg|
%li
= msg
.form-inputs
= f.input :title, label: "Title"
= f.input :notes, label: "Notes"
= f.input :enabled, label: "Enabled"
= f.input_field :parent_id, :as => :hidden, :value => @id
.form-group
.form-actions
= f.button :submit, {:class=>"btn btn-default"}
%br
= link_to 'Back', malfunctions_path, {:class=>"btn btn-default"}
Строка = f.input_field :parent_id, :as => :hidden, :value => @id говорит о том, что мы делаем не связанное с объектом скрытое поле, которое принимает значение @id из экшена new
Далее мы должны сделать экшен create, который отвечает за сохранение данных в таблицу базы данных:
..\app\controllers\malfunctions_controller.rb
class MalfunctionsController < ApplicationController
...
def create
#@parent_id = params[:malfunction][:parent_id].to_i || 0
@parent_id = params[:parent_id].to_i || 0 #тоже, что и выше
if @parent_id == 0
@malfunction = Malfunction.new(malfunction_params)
else
@current_malfunction = Malfunction.find(@parent_id)
@malfunction = @current_malfunction.children.new(malfunction_params)
end
respond_to do |format|
if @malfunction.save
format.html { redirect_to malfunctions_path, notice: 'Malfunction was successfully created.' }
format.json { render :index, status: :created, location: @malfunction }
else
format.html { render :new }
format.json { render json: @malfunction.errors, status: :unprocessable_entity }
end
end
end
def malfunction_params
params.require(:malfunction).permit(:title, :notes, :enabled, :parent_id)
end
Строка @malfunction = @current_malfunction.children.new(malfunction_params) являет собой сотворение children для объекта класса @current_malfunction см. доку на gem 'ancestry'
Далее сделаем эшен index, чтобы он отображал корневые malfunctions и при нажатии на кнопку list показывал children выбранной корневой malfunction
..\app\controllers\malfunctions_controller.rb
class MalfunctionsController < ApplicationController
...
def index
id = params[:parent_id].to_i || 0
if id == 0
@malfunctions = Malfunction.roots.order(:title).page params[:page]
elsif id != 0
@malfunctions = Malfunction.find(id).children.order(:title).page params[:page]
end
end
...
end
#.order(:title).page params[:page] - это пагинация
Соответствующая ему вьюха:
..\app\views\malfunctions\index.html.haml
%h1 Listing malfunctions
= link_to 'New Malfunction', new_malfunction_path
.center-block
= paginate @malfunctions
%table.table.table-striped.table-bordered.table-hover
%thead
%tr
%th ID
-#%th Parent ID
%th Title
%th New Sub_Malfunction
%th Sub Malfunctions Lists
%th Notes
%th Enabled
%th Destroy
%tbody
- @malfunctions.each do |t|
%tr
%td= t.id
-#%td= t.parent_id
%td= link_to t[:title], edit_malfunction_path(t)
%td= link_to 'New Sub_Malfunction', new_malfunction_path(:parent_id => t.id)
%td= link_to 'Lists', malfunctions_path(:parent_id => t.id)
%td= t.notes
%td= t.enabled
%td= link_to 'Destroy', t, :method => :delete, :data => { :confirm => 'Are you sure?' }
= paginate @malfunctions
#= link_to 'Lists', malfunctions_path(:parent_id => t.id) - переходит на вью _index_ с заданным _URL_ (:parent_id => t.id)
#= link_to 'New Sub_Malfunction', new_malfunction_path(:parent_id => t.id)- переходит на вью _new_ с заданным _URL_ (:parent_id => t.id)
##Настройки удаления в дереве Для того, чтобы при удалении родителя, его ребенок сам становился родителем, нужно добавить :orphan_strategy => :rootify к has_ancestry в модели:
..\app\models\malfunctions.rb
class Malfunction < ActiveRecord::Base
has_ancestry :orphan_strategy => :rootify
end
##Breadcrumbs with ancesrty Это пиздец!!! Проебался два дня!!!
Чтобы сделать Breadcrumbs для древовидной таблицы, в моем случае она зовется malfunctions, нужно:
-
сделать :cache_depth равным true, по дефолту он false, для этого делаем следующее:
-
открываем модель и добавляем в нее :cache_depth => :true и Malfunction.rebuild_depth_cache! так:
..\app\models\malfunctions.rb class Malfunction < ActiveRecord::Base has_ancestry :orphan_strategy => :rootify, :cache_depth => :true Malfunction.rebuild_depth_cache! end
-
добавляем в таблицу malfunctions, в базе данных, колонку :ancestry_depth, :integer, :default => 0 так, как сказано здесь: https://gist.github.com/elvisgiv/7688d3fd3c422d9ac8ca
-
-
изменить код в контроллере в index экшене:
..\app\controllers\malfunctions_controller.rb class MalfunctionsController < ApplicationController ... def index @id = params[:parent_id].to_i || 0 if @id == 0 @malfunctions = Malfunction.roots.order(:title).page params[:page] elsif @id != 0 @malfunctions = Malfunction.find(@id).children.order(:title).page params[:page] end if @id == 0 @malfunction = Malfunction.roots else @malfunction = Malfunction.find(@id).path(:from_depth => -100) end end ... end
да, блядь, его нужно отDRYить, но нахуй надо.
-
добавить следующий код во вьюху:
..\app\views\malfunctions\index.html.haml %div#breadcrumbs = link_to 'Home', malfunctions_path > - @malfunction.each do |a| = link_to a.title, malfunctions_path(:parent_id => a.id) if @id != 0 > %h1 Listing malfunctions ...
ВОТ и ВСЕ
пока что...