Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save elvisgiv/883569251a75db11b0f9 to your computer and use it in GitHub Desktop.
Save elvisgiv/883569251a75db11b0f9 to your computer and use it in GitHub Desktop.

#Создание дерева в таблице базы данных с помощью гема 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 
        &gt 
        - @malfunction.each do |a|
          = link_to a.title, malfunctions_path(:parent_id => a.id) if @id != 0
          &gt
      
      %h1 Listing malfunctions
      ...
    

ВОТ и ВСЕ

пока что...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment