### Defining a Rubanok Processor with Parameter Mapping Source: https://github.com/palkan/rubanok/blob/master/README.md Illustrates how to create a Rubanok processor by mapping incoming parameters to specific data transformations. This example shows mapping a search query parameter 'q' to a `search` method on the input data. ```ruby class CourseSessionsProcessor < Rubanok::Processor # You can map keys map :q do |q:| # `raw` is an accessor for input data raw.search(q) end end ``` -------------------------------- ### Rubanok Installation via Gemfile Source: https://github.com/palkan/rubanok/blob/master/README.md Shows how to add the Rubanok gem to a Rails project's Gemfile for installation. ```ruby gem "rubanok" ``` -------------------------------- ### Define Default Input Transformation with `prepare` Source: https://context7.com/palkan/rubanok/llms.txt The `prepare` method defines a transformation that executes before any rules are applied, but only if at least one rule matches. It's useful for initializing default data structures or performing setup transformations. If the input already matches the prepared structure, `prepare` returns nil. ```ruby class SearchQueryProcessor < Rubanok::Processor # Prepare is called before first matching rule prepare do next if raw&.dig(:query, :bool) { query: { bool: { must: [], filter: [] } } } end map :term do |term מד:| raw[:query][:bool][:must] << { match: { content: term } } raw end map :category do |category מד:| raw[:query][:bool][:filter] << { term: { category: category } } raw end map :date_from, :date_to do |date_from מד:, date_to מד:| raw[:query][:bool][:filter] << { range: { created_at: { gte: date_from, lte: date_to } } } raw end end # Without matching params, prepare is NOT called SearchQueryProcessor.call(nil, {}) # => nil # With matching params, prepare initializes the structure SearchQueryProcessor.call(nil, { term: "ruby", category: "programming" }) # => { # query: { # bool: { # must: [{ match: { content: "ruby" } }], # filter: [{ term: { category: "programming" } }] # } # } # } # When input already has the structure, prepare returns nil (no change) existing = { query: { bool: { must: [], filter: [] } } } SearchQueryProcessor.call(existing, { term: "rails" }) # => { query: { bool: { must: [{ match: { content: "rails" } }], filter: [] } } } ``` -------------------------------- ### Default Transformation with `prepare` Method in Ruby Source: https://github.com/palkan/rubanok/blob/master/README.md Demonstrates how to use the `prepare` method in a Rubanok Processor to define default transformations before any rules are applied. The `prepare` block can return a new initial value for the raw input or nil if no transformation is needed. It shows conditional execution and example calls. ```Ruby class CourseSearchQueryProcessor < Rubanok::Processor prepare do next if raw&.dig(:query, :bool) {query: {bool: {filters: []}}} end map :ids do |ids:| raw.dig(:query, :bool, :filters) << {terms: {id: ids}} raw end end ``` ```Ruby CourseSearchQueryProcessor.call(nil, {ids: [1]}) #=> {query {bool: {filters: [{terms: {ids: [1]}}]}}} ``` ```Ruby CourseSearchQueryProcessor.call({ids: [1]}) #=> {query {bool: {filters: [{terms: {ids: [1]}}]}}} ``` -------------------------------- ### Testing Rubanok Processors with RSpec Source: https://github.com/palkan/rubanok/blob/master/README.md Provides examples of how to test Rubanok processors in isolation using RSpec. It shows how to test the processor's logic directly and how to use the `have_rubanok_processed` matcher in controller tests to verify that the correct processing is applied. ```Ruby # For example, with RSpec RSpec.describe CourseSessionsProcessor do let(:input) { CourseSession.all } let(:params) { {} } subject { described_class.call(input, params) } specify "searching" do params[:q] = "wood" expect(subject).to eq input.search("wood") end end ``` ```Ruby RSpec.describe CourseSessionController do subject { get :index } specify do expect { subject }.to have_rubanok_processed(CourseSession.all) .with(CourseSessionsProcessor) end end ``` ```Ruby # To use `have_rubanok_processed` matcher you must add the following line to your `spec_helper.rb` / `rails_helper.rb` # require "rubanok/rspec" ``` -------------------------------- ### Accessing Processed Parameters in Rails Controller Source: https://github.com/palkan/rubanok/blob/master/README.md Shows how to use the `rubanok_process` and `rubanok_scope` methods within a Rails controller to process data and retrieve the parameters recognized by a Rubanok processor. `rubanok_scope` can be used to get a hash of recognized parameters, useful for displaying filter states. ```Ruby class CourseSessionController < ApplicationController def index @sessions = rubanok_process(CourseSession.all) @sessions_filter = rubanok_scope( params.permit(:q, :role_id), with: CourseSessionProcessor ) @sessions_filter = rubanok_scope #=> equals to rubanok_scope(params, with: implicit_rubanok_class) end end ``` -------------------------------- ### Using rubanok_scope for Active Filters in Views Source: https://context7.com/palkan/rubanok/llms.txt The `rubanok_scope` helper retrieves projected parameters recognized by the processor, which is useful for displaying active filters in views. It can be used directly in controllers to get recognized parameters or with explicit parameters and processor classes. It's also available as a view helper to check for present filters. ```ruby # app/controllers/products_controller.rb class ProductsController < ApplicationController def index @products = rubanok_process(Product.all) # Get params recognized by the processor @active_filters = rubanok_scope # Or with explicit params/processor @active_filters = rubanok_scope( params.permit(:q, :category, :min_price, :max_price), with: ProductsProcessor ) end end ``` ```erb # app/views/products/index.html.erb <% if rubanok_scope[:q].present? %>

Searching for: <%= rubanok_scope[:q] %>

<% end %> <% if rubanok_scope[:category].present? %>

Category: <%= rubanok_scope[:category] %>

<% end %> <%= link_to "Clear filters", products_path %> ``` -------------------------------- ### prepare - Define default input transformation Source: https://context7.com/palkan/rubanok/llms.txt The prepare method defines a transformation that runs before any rules are applied, but only if at least one rule matches. ```APIDOC ## prepare ### Description Initializes default data structures or performs setup transformations before processing rules are executed. ### Method N/A (DSL Method) ### Parameters - **block** (Proc) - Required - The transformation logic that returns the initialized structure or nil. ``` -------------------------------- ### Rubanok Processor and Scope Usage in Ruby Source: https://github.com/palkan/rubanok/blob/master/CHANGELOG.md Demonstrates how to define a custom processor using Rubanok's DSL for mapping and matching parameters. It also shows how to use `Process.project` to filter parameters and `rubanok_scope` within a Rails controller to obtain filtered parameters, optionally specifying a processor. ```ruby class PostsProcessor < Rubanok::Processor map(:q) { block } match(:page, :per_page, activate_on: :page) { block } end PostsProcessor.project(q: "search_me", filter: "smth", page: 2) # => { q: "search_me", page: 2 } class PostsController < ApplicationController def index @filter_params = rubanok_scope # or @filter_params = rubanok_scope params.require(:filter), with: PostsProcessor # ... end end ``` -------------------------------- ### Basic Rubanok Usage in Rails Controller Source: https://github.com/palkan/rubanok/blob/master/README.md Demonstrates how to integrate Rubanok into a Rails controller to process data using a defined processor. It shows the transformation from traditional chained query methods to a more concise Rubanok-based approach. ```ruby class CourseSessionController < ApplicationController def index @sessions = rubanok_process( # pass input CourseSession.all, # pass params params, # provide a processor to use with: CourseSessionsProcessor ) end end ``` ```ruby class CourseSessionController < ApplicationController def index @sessions = rubanok_process(CourseSession.all) end end ``` -------------------------------- ### Release Gem and Push Tags Source: https://github.com/palkan/rubanok/blob/master/RELEASING.md This command uses the `gem-release` tool to publish the gem to RubyGems. It also includes pushing tags to GitHub, which is crucial for version tracking. ```shell gem release -t git push --tags ``` -------------------------------- ### Inferring Processors with rubanok_process Source: https://context7.com/palkan/rubanok/llms.txt Demonstrates how to use the `rubanok_process` helper in a controller to automatically infer and apply a processor class. The processor is inferred based on the controller name (e.g., `Admin::PostsController` infers `Admin::PostsProcessor`). You can override this inference by defining an `implicit_rubanok_class` method. ```ruby class Admin::PostsController < ApplicationController def index # Infers Admin::PostsProcessor @posts = rubanok_process(Post.all) end # Override inference logic def implicit_rubanok_class PostsProcessor end end ``` -------------------------------- ### Apply Transformations with Processor.call Source: https://context7.com/palkan/rubanok/llms.txt The main entry point for applying transformation rules to data. It accepts input data and a parameters hash, returning the transformed result or the original input if no rules match. ```ruby class PostsProcessor < Rubanok::Processor map :q do |q:| raw.where("title ILIKE ?", "%#{q}%") end map :status do |status:| raw.where(status: status) end end # Basic usage posts = PostsProcessor.call(Post.all, { q: "ruby", status: "published" }) # Without matching params, input is returned unchanged posts = PostsProcessor.call(Post.all, {}) # Can omit input for non-database transformations result = MyProcessor.call({ ids: [1, 2, 3] }) ``` -------------------------------- ### Rubanok Processor with 'match' for Conditional Transformations Source: https://github.com/palkan/rubanok/blob/master/README.md Demonstrates the use of the `match` method in a Rubanok processor for conditional transformations based on parameter values. It includes handling specific values ('course_id', 'type') and a default case, along with input validation. ```ruby class CourseSessionsProcessor < Rubanok::Processor SORT_ORDERS = %w[asc desc].freeze SORTABLE_FIELDS = %w[id name created_at].freeze match :sort_by, :sort do having "course_id", "desc" do raw.joins(:courses).order("courses.id desc nulls last") end having "course_id", "asc" do raw.joins(:courses).order("courses.id asc nulls first") end # Match any value for the second arg having "type" do |sort: "asc"| # Prevent SQL injections raise "Possible injection: #{sort}" unless SORT_ORDERS.include?(sort) raw.joins(:course_type).order("course_types.name #{sort}") end # Match any value default do |sort_by:, sort: "asc"| raise "Possible injection: #{sort}" unless SORT_ORDERS.include?(sort) raise "The field is not sortable: #{sort_by}" unless SORTABLE_FIELDS.include?(sort_by) raw.order(sort_by => sort) end end # strict matching; if Processor will not match parameter, it will raise Rubanok::UnexpectedInputError # You can handle it in controller, for example, with sending 422 Unprocessable Entity to client match :filter, fail_when_no_matches: true do having "active" do raw.active end having "finished" do raw.finished end end end ``` -------------------------------- ### Rubanok Processor with Nested Processors Source: https://github.com/palkan/rubanok/blob/master/README.md Demonstrates how to define nested processors within a Rubanok processor using the `.process` method. This is useful for handling nested parameters, such as filtering by status within a broader filter context. ```ruby class CourseSessionsProcessor < Rubanok::Processor process :filter do match :status do having "draft" do raw.where(draft: true) end having "deleted" do raw.where.not(deleted_at: nil) end end # You can also use .map or even .process here end end ``` -------------------------------- ### Controlling Rule Activation with `activate_on` and `activate_always` Source: https://github.com/palkan/rubanok/blob/master/README.md Explains how to control the activation of rules in Rubanok processors. `activate_always: true` ensures a rule is always applied, using default values if necessary. `activate_on` specifies a key that must be present for the rule to activate, making it optional rather than required. ```Ruby # Always apply the rule; use default values for keyword args map :page, :per_page, activate_always: true do |page: 1, per_page: 2| raw.page(page).per(per_page) end ``` ```Ruby # Only require `sort_by` to be preset to activate sorting rule match :sort_by, :sort, activate_on: :sort_by do # ... end ``` -------------------------------- ### Push Code to GitHub Source: https://github.com/palkan/rubanok/blob/master/RELEASING.md This command pushes the local changes, including the version bump, to the remote GitHub repository. It's essential for CI to pass before releasing. ```shell git push ``` -------------------------------- ### Extract Recognized Parameters with `Processor.project` Source: https://context7.com/palkan/rubanok/llms.txt The `Processor.project` class method filters a given hash of parameters, returning only those that the processor is configured to recognize. This is useful for cleaning up input or constructing URLs based on filter state. ```ruby class OrdersProcessor < Rubanok::Processor map :q do |q מד:| raw.search(q) end map :status do |status מד:| raw.where(status: status) end map :page, :per_page, activate_always: true do |page: 1, per_page: 20| raw.page(page).per(per_page) end end # Get only recognized params all_params = { q: "test", status: "pending", unrelated: "value", page: 2 } OrdersProcessor.project(all_params) # => { q: "test", status: "pending", page: 2 } # Works with string keys too OrdersProcessor.project({ "q" => "search", "foo" => "bar" }) # => { q: "search" } ``` -------------------------------- ### Rubanok Processor with Multiple Parameter Mapping Source: https://github.com/palkan/rubanok/blob/master/README.md Shows a Rubanok processor mapping multiple parameters, 'page' and 'per_page', to a `paginate` method. It includes a default value for 'per_page' to handle cases where the parameter is not provided. ```ruby class CourseSessionsProcessor < Rubanok::Processor DEFAULT_PAGE_SIZE = 25 map :page, :per_page do |page:, per_page: DEFAULT_PAGE_SIZE| raw.paginate(page: page, per_page: per_page) end end ``` -------------------------------- ### Processor.project - Extract recognized parameters Source: https://context7.com/palkan/rubanok/llms.txt The project class method filters a hash to return only the parameters recognized by the processor. ```APIDOC ## Processor.project ### Description Extracts only the parameters that the processor is configured to handle from a given input hash. ### Parameters - **params** (Hash) - Required - The input hash containing potential parameters. ### Response - **result** (Hash) - A filtered hash containing only recognized parameters. ``` -------------------------------- ### Rubanok Global Configuration Options Source: https://context7.com/palkan/rubanok/llms.txt Rubanok offers global configuration options to control the behavior of rules, such as ignoring empty parameter values and handling unmatched parameters. These global settings can be overridden on a per-rule basis within processor classes. ```ruby # config/initializers/rubanok.rb # Ignore empty parameter values by default (default: true) # When true, params like { q: "" } or { q: nil } won't activate rules Rubanok.ignore_empty_values = true # Raise error when match rule has no matching clause (default: false) # When true, unmatched values raise Rubanok::UnexpectedInputError Rubanok.fail_when_no_matches = false # Per-rule configuration overrides global settings class StrictProcessor < Rubanok::Processor # This rule activates even for empty strings map :required_field, ignore_empty_values: false do |required_field:| raw.where(field: required_field) end # This match raises on invalid values regardless of global setting match :type, fail_when_no_matches: true do having "a" do raw.type_a end having "b" do raw.type_b end end end ``` -------------------------------- ### Processor.call Source: https://context7.com/palkan/rubanok/llms.txt The main entry point for applying transformation rules defined in a processor class to a dataset. ```APIDOC ## Processor.call ### Description Applies transformation rules to input data (e.g., ActiveRecord relation) based on a provided parameters hash. ### Method POST (Conceptual) ### Endpoint Processor.call(input_data, params) ### Parameters #### Request Body - **input_data** (Object) - Optional - The data structure to be transformed (e.g., ActiveRecord relation). - **params** (Hash) - Required - The parameters used to trigger specific transformation rules. ### Request Example { "q": "ruby", "status": "published" } ### Response #### Success Response (200) - **result** (Object) - The transformed data structure. ``` -------------------------------- ### Define Value-Matching Rules with match Source: https://context7.com/palkan/rubanok/llms.txt The 'match' method creates rules based on specific parameter values. It supports 'having' clauses for specific combinations, 'default' fallbacks, and strict validation. ```ruby class ArticlesProcessor < Rubanok::Processor match :filter do having "published" do raw.where(published: true) end having "draft" do raw.where(published: false) end end match :sort_by, :sort, activate_on: :sort_by do having "created_at", "desc" do raw.order(created_at: :desc) end default do |sort_by:, sort: "asc"| raw.order(sort_by => sort) end end end ``` -------------------------------- ### Bump Gem Version and Commit Source: https://github.com/palkan/rubanok/blob/master/RELEASING.md This snippet shows how to commit a version bump for a gem. It involves updating the version number in the `version.rb` file and then committing this change. ```shell git commit -m "Bump 1.." ``` -------------------------------- ### Filtering Input Values with `filter_with` in Ruby Source: https://github.com/palkan/rubanok/blob/master/README.md Demonstrates using the `filter_with` option in Rubanok's `.map` method to prepare input values before they are passed to the transforming block or to prevent rule activation. This can be done using a Proc or a class method, ensuring that only valid or non-empty values are processed. ```Ruby class PostsProcessor < Rubanok::Processor # We can pass a Proc map :ids, filter_with: ->(vals) { vals.reject(&:blank?).presence } do |ids:| raw.where(id: ids) end # or define a class method def self.non_empty_array(val) non_blank = val.reject(&:blank?) return if non_blank.empty? non_blank end # and pass its name as a filter_with value map :ids, filter_with: :non_empty_array do |ids:| raw.where(id: ids) end end ``` ```Ruby # Filtered values are used in rules PostsProcessor.call(Post.all, {ids: ["1", ""]}) == Post.where(id: ["1"]) ``` ```Ruby # When filter returns empty value, the rule is not applied PostsProcessor.call(Post.all, {ids: [nil, ""]}) == Post.all ``` -------------------------------- ### process - Define nested processors Source: https://context7.com/palkan/rubanok/llms.txt The process method allows for creating sub-processors to handle nested parameter structures, enabling complex filtering logic. ```APIDOC ## process ### Description Defines nested processors for handling complex or hierarchical parameter structures within a primary processor. ### Method N/A (DSL Method) ### Parameters - **name** (Symbol) - Required - The name of the nested parameter key. - **block** (Proc) - Required - The definition of nested mapping rules. ### Request Example params = { filter: { category: "electronics", brand: { name: "Apple" } } } ``` -------------------------------- ### Rails Controller Helper `rubanok_process` Source: https://context7.com/palkan/rubanok/llms.txt The `rubanok_process` method simplifies processing in Rails controllers by automatically inferring or accepting a specified processor class. It takes the base record set, controller parameters, and an optional processor class to apply the defined rules. ```ruby # app/processors/posts_processor.rb class PostsProcessor < Rubanok::Processor map :q do |q מד:| raw.where("title ILIKE ?", "%#{q}%") end map :category_id do |category_id מד:| raw.where(category_id: category_id) end map :page, :per_page, activate_always: true do |page: 1, per_page: 25| raw.page(page).per(per_page) end end # app/controllers/posts_controller.rb class PostsController < ApplicationController def index # Auto-infers PostsProcessor from controller name @posts = rubanok_process(Post.all) # Or specify processor explicitly @posts = rubanok_process(Post.all, params, with: PostsProcessor) # With custom params @posts = rubanok_process( Post.published, params.permit(:q, :category_id, :page, :per_page), with: PostsProcessor ) end end ``` -------------------------------- ### Define Nested Processors with `process` Source: https://context7.com/palkan/rubanok/llms.txt The `process` method in Rubanok allows for the creation of sub-processors to handle nested parameter structures, useful for complex filter objects or form data. It supports nested `map` and `match` rules, enabling hierarchical data processing. ```ruby class ProductsProcessor < Rubanok::Processor map :q do |q מד:| raw.search(q) end # Handle nested filter params process :filter do map :category do |category מד:| raw.where(category: category) end map :min_price, :max_price do |min_price: 0, max_price: Float::INFINITY| raw.where(price: min_price..max_price) end match :availability do having "in_stock" do raw.where("stock > 0") end having "out_of_stock" do raw.where(stock: 0) end end # Nested processors can be further nested process :brand do map :name do |name מד:| raw.joins(:brand).where(brands: { name: name }) end end end end # Usage with nested params params = { q: "laptop", filter: { category: "electronics", min_price: 500, max_price: 2000, availability: "in_stock", brand: { name: "Apple" } } } ProductsProcessor.call(Product.all, params) # => Product.all.search("laptop") # .where(category: "electronics") # .where(price: 500..2000) # .where("stock > 0") # .joins(:brand).where(brands: { name: "Apple" }) ``` -------------------------------- ### match - Value-Based Matching Source: https://context7.com/palkan/rubanok/llms.txt Defines rules that activate based on both parameter presence and specific parameter values. ```APIDOC ## match [parameter_keys] ### Description Creates rules that activate based on specific values of parameters. Supports multiple 'having' clauses and a 'default' fallback. ### Parameters #### Request Body - **parameter_keys** (Symbol) - Required - The parameter keys to match against. - **fail_when_no_matches** (Boolean) - Optional - If true, raises an error if no 'having' clause matches the input. ### Response - **transformed_data** (Object) - The data after applying the matched rule. ``` -------------------------------- ### map - Parameter Mapping Source: https://context7.com/palkan/rubanok/llms.txt Defines rules that activate when specific parameter keys are present in the input. ```APIDOC ## map [parameter_keys] ### Description Defines a transformation rule that executes when the specified parameter keys are present. Supports filtering and default values. ### Parameters #### Request Body - **parameter_keys** (Symbol) - Required - The parameter keys that trigger this rule. - **filter_with** (Proc/Symbol) - Optional - A filter or normalizer applied to the input value before processing. - **activate_always** (Boolean) - Optional - If true, the rule runs regardless of parameter presence. ### Response - **transformed_data** (Object) - The data after applying the logic defined in the block. ``` -------------------------------- ### Define Parameter-Based Rules with map Source: https://context7.com/palkan/rubanok/llms.txt The 'map' method defines rules that trigger when specific parameter keys are present. It supports default values, conditional activation, and input filtering. ```ruby class UsersProcessor < Rubanok::Processor map :q do |q:| raw.search(q) end map :page, :per_page, activate_always: true do |page: 1, per_page: 25| raw.page(page).per(per_page) end map :ids, filter_with: ->(vals) { vals.reject(&:blank?).presence } do |ids:| raw.where(id: ids) end def self.normalize_tags(val) Array(val).map(&:downcase).uniq.presence end map :tags, filter_with: :normalize_tags do |tags:| raw.where(tag: tags) end end ``` -------------------------------- ### Invoke Rubanok Processor in Controller Source: https://github.com/palkan/rubanok/blob/master/README.md Demonstrates the usage of rubanok_process within a controller action to filter data using the inferred processor class. ```ruby class CourseSessionsController < ApplicationController def index @sessions = rubanok_process(CourseSession.all, params) @sessions = CourseSessionsScoper.call(CourseSession.all, params.to_unsafe_h) end end ``` -------------------------------- ### Add RBS Type Annotations to Rubanok Processor Source: https://github.com/palkan/rubanok/blob/master/README.md Provides type hints for Rubanok DSL methods to assist the Steep type checker in resolving the correct context within instance_eval blocks. ```ruby class MyProcessor < Rubanok::Processor map :q do |q:| # @type self : Rubanok::Processor raw end match :sort_by, :sort, activate_on: :sort_by do # @type self : Rubanok::DSL::Matching::Rule having "status", "asc" do # @type self : Rubanok::Processor raw end # @type self : Rubanok::DSL::Matching::Rule default do |sort_by:, sort: "asc"| # @type self : Rubanok::Processor raw end end end ``` -------------------------------- ### rubanok_process - Rails controller helper Source: https://context7.com/palkan/rubanok/llms.txt A Rails controller helper method that processes input data using an inferred or specified processor class. ```APIDOC ## rubanok_process ### Description Processes input data against a processor class within a Rails controller context. ### Parameters - **scope** (Object) - Required - The initial data scope (e.g., ActiveRecord relation). - **params** (ActionController::Parameters) - Optional - The parameters to process. - **with** (Class) - Optional - The specific processor class to use if not inferred. ``` -------------------------------- ### RSpec Matchers for Controller and Processor Testing Source: https://context7.com/palkan/rubanok/llms.txt Rubanok provides RSpec matchers for testing controller actions and processor logic. The `have_rubanok_processed` matcher verifies that a controller action correctly applies a specified processor with given inputs and parameters. Processors can also be unit tested in isolation using `described_class.call`. ```ruby # spec/processors/posts_processor_spec.rb require "rails_helper" RSpec.describe PostsProcessor do let(:input) { Post.all } let(:params) { {} } subject { described_class.call(input, params) } describe "search" it "filters by query" do params[:q] = "ruby" expect(subject).to eq(input.where("title ILIKE ?", "%ruby%")) end end describe "pagination" it "applies default pagination" do expect(subject).to eq(input.page(1).per(25)) end it "uses provided page and per_page" do params[:page] = 3 params[:per_page] = 10 expect(subject).to eq(input.page(3).per(10)) end end describe "status filter" it "filters by published status" do params[:status] = "published" expect(subject).to eq(input.where(published: true)) end it "raises on invalid status" do params[:status] = "invalid" expect { subject }.to raise_error(Rubanok::UnexpectedInputError) end end end ``` ```ruby # spec/controllers/posts_controller_spec.rb require "rails_helper" require "rubanok/rspec" RSpec.describe PostsController, type: :controller do describe "GET #index" it "processes posts with PostsProcessor" do expect { get :index }.to have_rubanok_processed(Post.all) .with(PostsProcessor) end it "uses correct input class" do expect { get :index, params: { q: "test" } } .to have_rubanok_processed(Post).with(PostsProcessor) end end end ``` -------------------------------- ### Customize Implicit Processor Class in Rails Source: https://github.com/palkan/rubanok/blob/master/README.md Override the implicit_rubanok_class method in your ApplicationController to define custom naming conventions for your processor classes. ```ruby class ApplicationController < ActionController::Smth def implicit_rubanok_class "#{controller_path.classify.pluralize}Scoper".safe_constantize end end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.