Module: CrudComponents
- Defined in:
- lib/crud_components.rb,
lib/crud_components.rb,
lib/crud_components/model.rb,
lib/crud_components/query.rb,
lib/crud_components/action.rb,
lib/crud_components/config.rb,
lib/crud_components/engine.rb,
lib/crud_components/errors.rb,
lib/crud_components/markup.rb,
lib/crud_components/builder.rb,
lib/crud_components/helpers.rb,
lib/crud_components/version.rb,
lib/crud_components/fieldset.rb,
lib/crud_components/like_spec.rb,
lib/crud_components/structure.rb,
lib/crud_components/where_like.rb,
lib/crud_components/fields/base.rb,
lib/crud_components/typed_filter.rb,
lib/crud_components/dynamic_column.rb,
lib/crud_components/route_resolver.rb,
lib/crud_components/presenters/base.rb,
lib/crud_components/presenters/form.rb,
lib/crud_components/presenters/cells.rb,
lib/crud_components/fields/date_field.rb,
lib/crud_components/fields/enum_field.rb,
lib/crud_components/fields/json_field.rb,
lib/crud_components/fields/path_field.rb,
lib/crud_components/fields/text_field.rb,
lib/crud_components/presenters/filter.rb,
lib/crud_components/presenters/record.rb,
lib/crud_components/permission_context.rb,
lib/crud_components/presenters/actions.rb,
lib/crud_components/fields/string_field.rb,
lib/crud_components/fields/boolean_field.rb,
lib/crud_components/fields/dynamic_field.rb,
lib/crud_components/fields/numeric_field.rb,
lib/crud_components/fields/computed_field.rb,
lib/crud_components/fields/has_many_field.rb,
lib/crud_components/presenters/collection.rb,
lib/crud_components/fields/attachment_field.rb,
lib/crud_components/fields/belongs_to_field.rb,
lib/crud_components/presenters/cell_context.rb,
lib/crud_components/presenters/column_selection.rb,
lib/generators/crud_components/views/views_generator.rb,
lib/generators/crud_components/install/install_generator.rb
Defined Under Namespace
Modules: Fields, Generators, Helpers, LikeSpec, Markup, Model, Permission, Presenters, RouteResolver, WhereLike Classes: Action, Builder, Config, DefinitionError, DynamicColumn, Engine, Error, Fieldset, PermissionContext, Query, Structure, TypedFilter, UnknownFieldsetError
Constant Summary collapse
- RESERVED_PARAMS =
The query params the gem owns (filters are top-level params named after the field, so a field can't share these names). Declaring such an attribute raises in the Builder rather than silently colliding with sort/pagination.
%w[q sort dir page per cols].freeze
- NULL_FILTER_VALUE =
Sentinel filter value meaning "the column is NULL" (boolean/enum filters on nullable columns offer it as a "not set" choice). Improbable as a real value, so it never collides with a genuine enum key or boolean string.
'__null__'.freeze
- PRESENT_FILTER_VALUE =
The two non-blank values of an attachment presence filter — its 3-state control (any / present / absent) submits these, and the query turns them into an EXISTS / NOT EXISTS (
where.associated/where.missing) over the backing attachment association rather than a value match. See Fields::AttachmentField. 'present'.freeze
- ABSENT_FILTER_VALUE =
'absent'.freeze
- VERSION =
'0.2.0'.freeze
Class Method Summary collapse
-
.bundled_css ⇒ Object
The gem's stylesheet (the column-picker float styles), read once from the packaged file.
- .config ⇒ Object
- .configure {|config| ... } ⇒ Object
-
.permitted_attributes(model, action: :update, ability: nil) ⇒ Object
The strong-params permit list for a model's derived form — the same field metadata the form renders from, so the two can't drift.
-
.previews_available? ⇒ Boolean
private
Whether non-image attachment previews (e.g. a PDF's first page) can actually be generated here.
-
.selected(scope, params, param: :selected) ⇒ Object
Resolve a bulk-action selection from request params into a relation.
-
.selected_columns(params, param_prefix: nil) {|names| ... } ⇒ Object
The column-picker selection from a request's params: the ordered list of column names the user ticked, or nil when the picker wasn't submitted.
- .structure_for(model) ⇒ Object
-
.where_like(relation, spec, value) ⇒ Object
Safe case-insensitive contains-match on any relation, using the same escaped-ILIKE machinery as
filter like:/search_in— so you never hand-writewhere("col LIKE ?", "%#{value}%")(which forgets to escape the user's%/_).
Class Method Details
.bundled_css ⇒ Object
The gem's stylesheet (the column-picker float styles), read once from the
packaged file. Backs the crud_components_styles helper, which inlines it;
the same file is also linkable via stylesheet_link_tag "crud_components"
on hosts whose asset pipeline serves engine assets.
162 163 164 |
# File 'lib/crud_components.rb', line 162 def bundled_css @bundled_css ||= File.read(File.('../app/assets/stylesheets/crud_components.css', __dir__)) end |
.config ⇒ Object
60 61 62 |
# File 'lib/crud_components.rb', line 60 def config @config ||= Config.new end |
.configure {|config| ... } ⇒ Object
64 65 66 |
# File 'lib/crud_components.rb', line 64 def configure yield config end |
.permitted_attributes(model, action: :update, ability: nil) ⇒ Object
The strong-params permit list for a model's derived form — the same field metadata the form renders from, so the two can't drift. Use in a controller:
params.require(:book)
.permit(*CrudComponents.permitted_attributes(Book, action: :update,
ability: current_ability))
139 140 141 |
# File 'lib/crud_components.rb', line 139 def permitted_attributes(model, action: :update, ability: nil) Structure.for(model).permitted_params(action, PermissionContext.new(ability)) end |
.previews_available? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Whether non-image attachment previews (e.g. a PDF's first page) can
actually be generated here. Beyond a previewer binary (poppler/ffmpeg,
which previewable? already checks), processing needs image_processing
plus the configured variant backend's gem (ruby-vips or mini_magick).
When any is missing, the renderer shows an icon + filename rather than a
preview that would 500 at processing time.
120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/crud_components.rb', line 120 def previews_available? return @previews_available if defined?(@previews_available) @previews_available = begin require 'image_processing' processor = defined?(ActiveStorage) ? ActiveStorage.variant_processor : :vips require(processor.to_s == 'mini_magick' ? 'mini_magick' : 'vips') true rescue LoadError false end end |
.selected(scope, params, param: :selected) ⇒ Object
Resolve a bulk-action selection from request params into a relation. The
row checkboxes submit selected[]=<identify_by> (a slug array; a comma
string is also accepted).
Pass the same authorized scope you'd render — selection narrows within it, so a tampered slug can never reach a row outside it:
CrudComponents.selected(@books, params).destroy_all # @books already scoped
A model class also works when you don't scope (acts on the whole table):
CrudComponents.selected(Book, params)
152 153 154 155 156 |
# File 'lib/crud_components.rb', line 152 def selected(scope, params, param: :selected) model = scope.respond_to?(:klass) ? scope.klass : scope values = Array(params[param]).flat_map { |v| v.to_s.split(',') }.map(&:strip).reject(&:blank?) scope.where(Structure.for(model).identify_by => values) end |
.selected_columns(params, param_prefix: nil) {|names| ... } ⇒ Object
The column-picker selection from a request's params: the ordered list of
column names the user ticked, or nil when the picker wasn't submitted.
Honors param_prefix: (match it to the picker's). Persist it however you
like, then feed it back via picked_columns:.
cols = CrudComponents.selected_columns(params)
current_user.update!(book_columns: cols) if cols
A block runs only when a selection was submitted, and receives the list:
CrudComponents.selected_columns(params) { |cols| current_user.update!(book_columns: cols) }
Accepts both the no-JS cols[]=a&cols[]=b array and the comma-joined
cols=a,b the crud-columns controller submits.
103 104 105 106 107 108 109 110 111 |
# File 'lib/crud_components.rb', line 103 def selected_columns(params, param_prefix: nil) key = param_prefix ? "#{param_prefix}_cols" : 'cols' raw = params[key] || params[key.to_sym] list = raw.is_a?(Array) ? raw : raw.is_a?(String) ? raw.split(',') : nil names = list&.map { |n| n.to_s.strip }&.reject(&:blank?) names = nil if names.nil? || names.empty? yield names if block_given? && names names end |
.structure_for(model) ⇒ Object
68 69 70 |
# File 'lib/crud_components.rb', line 68 def structure_for(model) Structure.for(model) end |
.where_like(relation, spec, value) ⇒ Object
Safe case-insensitive contains-match on any relation, using the same
escaped-ILIKE machinery as filter like: / search_in — so you never
hand-write where("col LIKE ?", "%#{value}%") (which forgets to escape the
user's %/_). The scope handed to a filter/search block already carries
#where_like; this module function is for the relations you build yourself,
e.g. a subquery on another model:
filter: ->(scope, value) {
ids = CrudComponents.where_like(PropertyValue.where(definition: prop), :value, value)
scope.where(id: ids.select(:subject_id))
}
spec is a LikeSpec spec (:value, %i[a b], { assoc: :col }).
85 86 87 |
# File 'lib/crud_components.rb', line 85 def where_like(relation, spec, value) LikeSpec.apply(relation, spec, value) end |