Skip to content

Commit

Permalink
adding in --record-scope option (#182)
Browse files Browse the repository at this point in the history
* adding in --record-scope option

* option to have last paramter in the path produced by  optionalized ternary be always instance variable

* the app's controller methods were never actually in scope here so i'm not sure why I was tryin gto eval them

* don't use policy_scope() around new objects; this was wrong

* make --big-edits always go back to list view via HTML update (data-turbo: false)

* big edit always does html false; improvements to how parent objects are passed into nested partials
'

* makes magic buttons use data-tubro: false if big_edit; refactors to how nested and nested_for is handedled

* specs

* fixes syntax error in _line; fixes current user to only respect --auth setting; fixes datetime field to output using .change(sec: 0)

* spec

* release notes for 0.6.9

* Fixes"
  • Loading branch information
jasonfb authored Dec 14, 2024
1 parent 762a197 commit c88a25b
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 56 deletions.
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,23 @@ The 'Abcs' portal will display as 5 bootstrap columns instead of the typical 4.
This puts the downnested portals on top of one another (stacked top to bottom) instead of side-by-side (left to right). This is useful if you have a lot of downnested portals and you want to keep the page from getting too wide.



### `--record-scope=`

Record scope allows you to apply a model based scope for the controller being generated.
This is applied on top of all other scopes, searches, and modifiers applied to the

`bin/rails :generate hot_glue:scaffold Order --record-scope='.is_open'`

Be sure to use single quotes (') and don't forget the dot (`.`) before your scope(s).

Make sure your Order model has a scope `is_open`
```
scope :is_open, -> {where(state == 'open')}
```

Now all records displayed through the generated controller

## FLAGS (Options with no values)
These options (flags) also uses `--` syntax but do not take any values. Everything is assumed (default) to be false unless specified.

Expand Down Expand Up @@ -999,10 +1016,17 @@ Omits list views.

### `--big-edit`

If you do not want inline editing of your list items but instead want to fall back to full page style behavior for your edit views, use `--big-edit`. Turbo still handles the page interactions, but the user is taken to a full-screen edit page instead of an edit-in-place interaction.
If you do not want inline editing of your list items but instead want to fallback to full-page style behavior for your edit views, use `--big-edit`.

The user will be taken to a full-screen edit page instead of an edit-in-place interaction.

When using `--big-edit`, any downnested portals will be displayed on the edit page instead of on the list page.

Big edit makes all edit and magic button operations happen using `'data-turbo': false`, fully reloading the page and submitting HTML requests instead of TURBO_STREAM requests.

Likewise, the controller's `update` action always redirects instead of using Turbo.


### `--display-list-after-update`

After an update-in-place normally only the edit view is swapped out for the show view of the record you just edited.
Expand Down Expand Up @@ -1662,6 +1686,24 @@ These automatic pickups for partials are detected at buildtime. This means that

# VERSION HISTORY

#### 2024-12-12 v0.6.9

`--record-scope`
Record scope allows you to apply a model based scope for the controller being generated.
This is applied on top of all other scopes, searches, and modifiers applied to the

`bin/rails :generate hot_glue:scaffold Order --record-scope='.is_open'`

Be sure to use single quotes (') and don't forget the dot (`.`) before your scope(s).

Make sure your Order model has a scope `is_open`

`--big-edit` now always uses non-turbo form submits, for update + magic buttons
• refactor of modified datetime feature to prefer current user as set by the --auth setting (will not work in @gd mode). future implemenation will further refine
• when using big edit, `update.turbo_stream.erb` is no longer written
• removes Pundit policy_scope() around new operations
• refactors to how parent objects from a nested controller pass these variables to lower-level partials; this implementation hard-cards the nested set as locals and also builds a `nested_for` key (string)


#### 2024-12-05 - v0.6.8
• fixes in modify_date_inputs_on_params for current_user_object
Expand Down
2 changes: 1 addition & 1 deletion lib/generators/hot_glue/fields/date_time_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def spec_list_view_natural_assertion
end

def form_field_output
"<%= datetime_field_localized(f, :#{name}, #{singular}.#{name}, label: '#{ name.to_s.humanize }' ) %>"
"<%= f.datetime_field( :#{name}, value: #{singular}.#{name} && #{singular}.#{name}.change(sec: 0), class: '#{@layout_strategy.form_input_class}' ) %>"
end

def viewable_output
Expand Down
4 changes: 4 additions & 0 deletions lib/generators/hot_glue/layout_strategy/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def search_opening
""
end

def form_input_class
""
end

def search_closing
""
end
Expand Down
4 changes: 4 additions & 0 deletions lib/generators/hot_glue/layout_strategy/bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ def form_checkbox_label_class
"form-check-label"
end

def form_input_class
"form-control"
end

def search_opening
'<div class="row"><div class="col-md-12 card"><div class="card-body">'
end
Expand Down
9 changes: 7 additions & 2 deletions lib/generators/hot_glue/markup_templates/erb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,14 @@ def add_spaces_each_line(text, num_spaces)
text.lines.collect{|line| add_spaces + line}.join("")
end

def magic_button_output(path:, singular:, magic_buttons:, small_buttons: )
def magic_button_output(path:,
singular:,
big_edit: ,
magic_buttons:, small_buttons: )
magic_buttons.collect{ |button_name|
"<%= form_with model: #{singular}, url: #{path}, html: {style: 'display: inline', data: {\"turbo-confirm\": 'Are you sure you want to #{button_name} this #{singular}?'}} do |f| %>" +
"<%= form_with model: #{singular}, url: #{path}, html: {style: 'display: inline', data: {\"turbo-confirm\": 'Are you sure you want to #{button_name} this #{singular}?' " +
(big_edit ? ", \"turbo\": false" : "") +
"}} do |f| %>" +
"<%= f.hidden_field :__#{button_name}, value: \"__#{button_name}\" %>" +
"<%= f.submit '#{button_name.titleize}'.html_safe, disabled: (#{singular}.respond_to?(:#{button_name}able?) && ! #{singular}.#{button_name}able? ), class: '#{singular}-button #{@layout_strategy.button_applied_classes} #{@layout_strategy.magic_button_classes}' %>" +
"<% end %>"
Expand Down
63 changes: 41 additions & 22 deletions lib/generators/hot_glue/scaffold_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
:display_as, :downnest_children, :downnest_object, :hawk_keys, :layout_object,
:modify_as,
:nest_with, :path, :plural, :sample_file_path, :show_only_data, :singular,
:singular_class, :smart_layout, :stacked_downnesting, :update_show_only, :ownership_field,
:layout_strategy, :form_placeholder_labels, :form_labels_position, :pundit,
:self_auth, :namespace_value, :related_sets, :search_clear_button, :search_autosearch
:singular_class, :smart_layout, :stacked_downnesting,
:update_show_only, :ownership_field,
:layout_strategy, :form_placeholder_labels,
:form_labels_position, :pundit,
:self_auth, :namespace_value, :record_scope, :related_sets,
:search_clear_button, :search_autosearch
# important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
# so we use namespace_value instead

Expand Down Expand Up @@ -97,6 +100,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
class_option :code_after_create, default: nil
class_option :code_before_update, default: nil
class_option :code_after_update, default: nil
class_option :record_scope, default: nil


class_option :search, default: nil # set or predicate

Expand Down Expand Up @@ -335,6 +340,7 @@ def initialize(*meta_args)
@new_in_modal = options['new_in_modal'] || false

@smart_layout = options['smart_layout']
@record_scope = options['record_scope']

@pundit = options['pundit']
if @pundit.nil?
Expand Down Expand Up @@ -1195,10 +1201,16 @@ def auth_object
end

def current_user_object
default_current_user = options['auth'] || "current_user"
if eval("defined?(#{default_current_user})")
default_current_user
else

# TODO: in god mode, there's no way for the time input
# to know who the current user under this design
# for timeinput = user_centered , we need to know who the current user is
# so we can set the time zone to the user's time zone
#
if options['auth']
options['auth']
elsif @god
# do we use current_user here
"nil"
end
end
Expand All @@ -1209,14 +1221,15 @@ def no_devise_installed

def magic_button_output
@template_builder.magic_button_output(
path: HotGlue.optionalized_ternary(namespace: @namespace,
target: @singular,
nested_set: @nested_set,
with_params: true,
put_form: true),
singular: singular,
magic_buttons: @magic_buttons,
small_buttons: @small_buttons
path: HotGlue.optionalized_ternary( namespace: @namespace,
target: @singular,
nested_set: @nested_set,
with_params: true,
put_form: true),
big_edit: @big_edit,
singular: singular,
magic_buttons: @magic_buttons,
small_buttons: @small_buttons
)
end

Expand Down Expand Up @@ -1245,7 +1258,6 @@ def copy_view_files
formats.each do |format|
source_filename = cc_filename_with_extensions("#{@markup}/#{view}", "#{@markup}")
dest_filename = cc_filename_with_extensions("#{view}", "#{@markup}")
# byebug
dest_filepath = File.join("#{filepath_prefix}app/views#{namespace_with_dash}",
@controller_build_folder, dest_filename)

Expand Down Expand Up @@ -1361,7 +1373,10 @@ def turbo_stream_views

unless @no_edit
res << 'edit'
res << 'update'

unless @big_edit
res << 'update'
end
end

res
Expand Down Expand Up @@ -1527,10 +1542,12 @@ def load_all_code
end

if pundit
res << " @#{ plural_name } = policy_scope(#{ object_scope }).page(params[:page])#{ n_plus_one_includes }#{ ".per(per)" if @paginate_per_page_selector }"
res << " @#{ plural_name } = policy_scope(#{ object_scope })#{record_scope}.page(params[:page])#{ n_plus_one_includes }#{ ".per(per)" if @paginate_per_page_selector }"
else
if !@self_auth
res << spaces(4) + "@#{ plural_name } = #{ object_scope.gsub("@",'') }#{ n_plus_one_includes }.page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"

res << spaces(4) + "@#{ plural_name } = #{ object_scope.gsub("@",'') }#{ n_plus_one_includes }#{record_scope}"

if @search_fields
res << @search_fields.collect{ |field|
wqs = @columns_map[field.to_sym].where_query_statement
Expand All @@ -1539,12 +1556,14 @@ def load_all_code
end
}.compact.join
end
res << ".page(params[:page])#{ '.per(per)' if @paginate_per_page_selector }"

elsif @nested_set[0] && @nested_set[0][:optional]
res << "@#{ plural_name } = #{ class_name }.all"
res << "@#{ plural_name } = #{ class_name }.#{record_scope}.all"
else
res << "@#{ plural_name } = #{ class_name }.where(id: #{ auth_object.gsub("@",'') }.id)#{ n_plus_one_includes }"
res << "@#{ plural_name } = #{ class_name }.#{record_scope}.where(id: #{ auth_object.gsub("@",'') }.id)#{ n_plus_one_includes }"

res << ".page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"
res << "#{record_scope}.page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"
end
end
res << "\n"
Expand Down
27 changes: 16 additions & 11 deletions lib/generators/hot_glue/templates/controller.rb.erb
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,20 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
<% if !@self_auth %>
def load_<%= singular_name %>
<% if @nested_set[0] && @nested_set[0][:optional] %>if params.include?(:<%= @nested_set.last[:singular] %>_id)
@<%= singular_name %> = <%= object_scope.gsub("@",'') %>.find(params[:id])
else <% end %>@<%= singular_name %> = <%= object_scope %>.find(params[:id])<% if @nested_set[0] && @nested_set[0][:optional] %>
@<%= singular_name %> = <%= object_scope.gsub("@",'') %><%= @record_scope %>.find(params[:id])
else <% end %>@<%= singular_name %> = <%= object_scope %><%= @record_scope %>.find(params[:id])<% if @nested_set[0] && @nested_set[0][:optional] %>
end<% end %>
end
<% else %>
def load_<%= singular_name %>
@<%= singular_name %> = (<%= auth_object.gsub("@",'') %><%= " if params.include?(:#{@nested_set[0][:singular]}_id)" if @nested_set.any? && @nested_set[0][:optional] %>)<% if @nested_set.any? && @nested_set[0][:optional] %> || <%= class_name %>.find(params[:id])<% end %>
@<%= singular_name %> = (<%= auth_object.gsub("@",'') %><%= " if params.include?(:#{@nested_set[0][:singular]}_id)" if @nested_set.any? && @nested_set[0][:optional] %>)<% if @nested_set.any? && @nested_set[0][:optional] %> || <%= class_name %>.find(params[:id])<% end %><%= @record_scope %>
end<% end %>
<% if @paginate_per_page_selector %>def per
params[:per] || 10
end<% end %>
<% unless @no_list %>
def load_all_<%= plural %>
<%= load_all_code %>
<%= load_all_code %>
end

def index<% if @search == "set" %>
Expand All @@ -88,9 +88,9 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
end<% end %>

<% if create_action %> def new<% if @object_owner_sym %>
@<%= singular_name %> = <% if @pundit %>policy_scope(<% end %><%= class_name %><% if @pundit %>)<% end %>.new<% if eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>(<%= @object_owner_sym %>: <%= @object_owner_eval %>)<% end %><% elsif @object_owner_optional && any_nested? %>
@<%= singular_name %> = <% if @pundit %>policy_scope(<% end %><%= class_name %><% if @pundit %>)<% end %>.new({}.merge(<%= @nested_set.last[:singular] %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}))<% else %>
@<%= singular_name %> = <% if @pundit %>policy_scope(<% end %><%= class_name %><% if @pundit %>)<% end %>.new(<% if any_nested? %><%= @object_owner_sym %>: <%= @object_owner_eval %><% end %>)<% end %>
@<%= singular_name %> = <%= class_name %>.new<% if eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>(<%= @object_owner_sym %>: <%= @object_owner_eval %>)<% end %><% elsif @object_owner_optional && any_nested? %>
@<%= singular_name %> = <%= class_name %>.new({}.merge(<%= @nested_set.last[:singular] %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}))<% else %>
@<%= singular_name %> = <%= class_name %>.new(<% if any_nested? %><%= @object_owner_sym %>: <%= @object_owner_eval %><% end %>)<% end %>
<% if @pundit %>authorize @<%= singular_name %><% end %><% if @pundit %>
@action = 'new'
rescue Pundit::NotAuthorizedError
Expand All @@ -101,7 +101,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>

def create
flash[:notice] = +''
modified_params = modify_date_inputs_on_params(<%= singular_name %>_params.dup, <%= current_user_object %>, <%= datetime_fields_list %>)<% if @object_owner_sym && eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>
modified_params = modify_date_inputs_on_params(<%= singular_name %>_params.dup, <%= current_user_object %>, <%= datetime_fields_list %>)<% if @object_owner_sym && eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>
modified_params = modified_params.merge(<%= @object_owner_sym %>: <%= @object_owner_eval %>) <% elsif @object_owner_optional && any_nested? %>
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% end %>

Expand All @@ -123,6 +123,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
nested_set: @nested_set,
modifier: 'edit_',
with_params: true,
instance_last_item: true,
put_form: true).gsub("(#{singular}", "(@#{singular}") %><% end %>
else
flash[:alert] = "Oops, your <%= singular_name %> could not be created. #{@hawk_alarm}"
Expand All @@ -138,11 +139,13 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
<% unless @no_edit %>
def show<% if @pundit %>
authorize @<%= singular %><% end %>
redirect_to <%= HotGlue.optionalized_ternary(namespace: @namespace,
redirect_to <%= HotGlue.optionalized_ternary(namespace: @namespace,
target: @singular,
top_level: false,
nested_set: @nested_set,
modifier: 'edit_',
with_params: true,
instance_last_item: true,
put_form: true).gsub("(#{singular}", "(@#{singular}") %>
end

Expand All @@ -165,7 +168,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
end
<% end %>

modified_params = modify_date_inputs_on_params(<% if @update_show_only %>update_<% end %><%= singular_name %>_params.dup<%= controller_update_params_tap_away_magic_buttons %>, <%= current_user_object %>, <%= datetime_fields_list %>) <% if @object_owner_sym && eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>
modified_params = modify_date_inputs_on_params(<% if @update_show_only %>update_<% end %><%= singular_name %>_params.dup<%= controller_update_params_tap_away_magic_buttons %>, <%= current_user_object %>, <%= datetime_fields_list %>)<% if @object_owner_sym && eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>
modified_params = modified_params.merge(<%= @object_owner_sym %>: <%= @object_owner_eval %>) <% elsif @object_owner_optional && any_nested? %>
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% end %>
<% if @pundit %><% @related_sets.each do |key, related_set| %>
Expand All @@ -186,7 +189,9 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
<% if @display_list_after_update %> load_all_<%= plural %><% end %>
flash[:notice] << "Saved #{@<%= singular %>.<%= display_class %>}"
flash[:alert] = @hawk_alarm if @hawk_alarm
<% unless @big_edit %>render :update, status: :unprocessable_entity<% else %>redirect_to <%= @namespace %>_<%= @plural %>_path<% end %>
<% unless @big_edit %>render :update, status: :unprocessable_entity<% else %>
redirect_to <%= path_helper_plural(false) %>
<% end %>
else
flash[:alert] = "<%= singular_name.titlecase %> could not be saved. #{@hawk_alarm}"
@action = 'edit'
Expand Down
2 changes: 1 addition & 1 deletion lib/generators/hot_glue/templates/erb/_edit.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<\%= render(partial: "<%= namespace_with_trailing_dash %>errors", locals: {resource: <%= singular %> }) %>
<\% end %>
<h2>Editing <\%= <%= singular %>.<%= display_class %> %></h2>
<\%= form_with model: <%= singular %>, url: <%= form_path_edit_helper %> do |f| %>
<\%= form_with model: <%= singular %>, url: <%= form_path_edit_helper %><%= ", html: {'data-turbo': false}" if @big_edit %> do |f| %>
<\%= render partial: "<%= namespace_with_trailing_dash + @controller_build_folder + "/" %>form", locals: {:<%= singular %> => <%= singular %>, f: f}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> \%>
<% if @edit_within_form_partial %><\%= render partial: "edit_within_form", locals: {f: f, <%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
<\% end %>
Expand Down
Loading

0 comments on commit c88a25b

Please sign in to comment.