Class: IntrospectiveAdmin::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/introspective_admin/base.rb

Class Method Summary collapse

Class Method Details

.column_list(model, extras = []) ⇒ Object



36
37
38
39
40
41
# File 'lib/introspective_admin/base.rb', line 36

def column_list(model, extras = [])
  model.columns.map { |c|
    ref_name = c.name.sub(/(_type|_id)$/, '')
    model.reflections[ref_name] ? ref_name : c.name
  }.uniq - %w[created_at updated_at] - exclude_params + extras
end

.exclude_paramsObject



24
25
26
# File 'lib/introspective_admin/base.rb', line 24

def exclude_params
  [] # do not display the field in the index page and forms.
end

.include_virtual_attributesObject



28
29
30
# File 'lib/introspective_admin/base.rb', line 28

def include_virtual_attributes
  []
end


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/introspective_admin/base.rb', line 49

def link_record(dsl, record)
  link_text = record.try(:name) || record.try(:title) || record.class.to_s
  link_href = begin begin
    dsl.send("admin_#{record.class.name.underscore}_path", record.id)
  rescue StandardError
    false
  end
  end
  if link_href
    dsl.link_to link_text, link_href
  elsif link_text
    link_text
  else
    record
  end
end

.params_list(model, extras = []) ⇒ Object



43
44
45
46
47
# File 'lib/introspective_admin/base.rb', line 43

def params_list(model, extras = [])
  model.columns.map { |c|
    polymorphic?(model, c.name) ? "#{c.name.sub(/_id$/, '')}_assign" : c.name
  } + extras
end

.polymorphic?(model, column) ⇒ Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/introspective_admin/base.rb', line 32

def polymorphic?(model, column)
  (model.reflections[column.sub(/_id$/, '')].try(:options) || {})[:polymorphic]
end

.register(model, &block) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/introspective_admin/base.rb', line 66

def register(model, &block)
  # Defining activeadmin pages will break pending migrations:
  begin begin
    ActiveRecord::Migration.check_all_pending!
  rescue StandardError
    return
  end
  end

  klass         = self
  model_name    = model.to_s.underscore
  nested_config = model.nested_attributes_options.reject { |name, _o|
    klass.exclude_params.include?("#{name}_attributes")
  }.to_h do |assoc, options|
    reflection       = model.reflections[assoc.to_s]
    reflection_class = reflection.class_name.constantize
    # merge the options of the nested attribute and relationship declarations
    options = options.merge(reflection_class.reflections[assoc.to_s].try(:options) || {})
    options[:class]   = reflection_class
    options[:columns] = klass.column_list(reflection_class)
    options[:params]  = klass.params_list(reflection_class)
    options[:reflection]            = reflection
    options[:polymorphic_reference] = reflection.options[:as].to_s
    [assoc, options]
  end

  ActiveAdmin.register model do
    instance_eval(&block) if block_given? # Evalutate the passed black for overrides to the defaults

    controller do
      def scoped_collection
        super.includes super.nested_attributes_options.keys
      end
    end

    index do
      selectable_column
      cols = model.columns.map(&:name) - klass.exclude_params
      cols.each_with_index do |c, _i|
        reflection = model.reflections.detect { |_k, v| v.foreign_key == c }
        if reflection
          column c do |o|
            klass.link_record(self, o.send(reflection.first))
          end
        else
          column c
        end
      end
      actions
    end

    show do
      instance = send(model_name)

      attributes_table do
        model.columns.each do |c|
          next if c.name =~ /password/

          reflection = model.reflections.detect { |_k, v| v.foreign_key == c.name }
          if reflection
            row c.name do |_o|
              klass.link_record(self, instance.send(reflection.first))
            end
          else
            row c.name
          end
        end

        nested_config.each do |assoc, options|
          panel assoc.capitalize do
            table_for instance.send(assoc) do
              options[:columns].each do |c|
                if options[:class].reflections[c]
                  column(c) do |r|
                    klass.link_record(self, r.send(c)) if r
                  end
                else
                  column c
                end
              end

              admin_route = begin begin
                url_for(['admin', options[:class].name.underscore])
              rescue StandardError
                false
              end
              end
              if admin_route
                column 'actions' do |child|
                  span link_to 'View',   url_for(['admin', child])
                  span link_to 'Edit',   url_for(['edit', 'admin', child])
                  span link_to 'Delete', url_for(['admin', child]), method: :delete, confirm: 'Are you sure you want to delete this?'
                end
              end
            end
          end
        end
      end
    end

    permitted_params = klass.params_list(model, klass.include_virtual_attributes) + [nested_config.to_h do |assoc, o|
      ["#{assoc}_attributes", o[:params] + [(o[:allow_destroy] ? :_destroy : '')]]
    end]
    permit_params(*permitted_params)

    form do |f|
      f.semantic_errors(*f.object.errors.messages.keys)
      f.actions

      klass.column_list(model, klass.include_virtual_attributes).each do |column|
        next if column == model.primary_key

        if klass.polymorphic?(model, column)
          f.input "#{column}_assign", collection: model.send("#{column}_assign_options")
        elsif model.respond_to?("options_for_#{column}")
          f.input column, collection: model.send("options_for_#{column}", f.object)
        else
          f.input column
        end
      end

      div { '&nbsp'.html_safe }

      nested_config.each do |assoc, options|
        aclass  = options[:class]
        columns = options[:columns] - [aclass.primary_key]
        f.inputs do
          f.has_many assoc, allow_destroy: options[:allow_destroy] do |r|
            columns.each do |c|
              if c == model_name || c == options[:polymorphic_reference]
                # the join to the parent is implicit
              elsif klass.polymorphic?(aclass, c)
                r.input "#{c}_assign", collection: aclass.send("#{c}_assign_options")
              elsif aclass.reflections[c] && aclass.respond_to?("options_for_#{c}")
                # If the class has an options_for_<column> method defined use that
                # rather than the default behavior, pass the instance for scoping,
                # e.g. UserProjectJob.options_for_job is scoped by the Project's
                # jobs:
                r.input c, collection: aclass.send("options_for_#{c}", f.object)
              else
                r.input c
              end
            end
          end
        end
      end
    end
  end
end