"rails/rails", branch: "main" gem "rails", "~> 8.0.0.rc1" # The modern asset pipeline for Rails [https://github.com/rails/propshaft] gem "propshaft" # Use sqlite3 as the database for Active Record gem "sqlite3", ">= 2.1" # Use the Puma web server [https://github.com/puma/puma] gem "puma", ">= 5.0" # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] gem "importmap-rails" # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] gem "turbo-rails" # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] gem "stimulus-rails" # Build JSON APIs with ease [https://github.com/rails/jbuilder] gem "jbuilder" # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] # gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem "tzinfo-data", platforms: %i[ windows jruby ] # Use the database-backed adapters for Rails.cache, Active Job, and Action Cable gem "solid_cache" gem "solid_queue" gem "solid_cable" # Reduces boot times through caching; required in config/boot.rb gem "bootsnap", require: false # Deploy this application anywhere as a Docker container [https://kamal-deploy.org] gem "kamal", require: false # Add HTTP asset caching/compression and X-Sendfile acceleration to Puma [https://github.com/basecamp/thruster/] gem "thruster", require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" # Static analysis for security vulnerabilities [https://brakemanscanner.org/] gem "brakeman", require: false # Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/] gem "rubocop-rails-omakase", require: false end group :development do # Use console on exceptions pages [https://github.com/rails/web-console] gem "web-console" end group :test do # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] gem "capybara" gem "selenium-webdriver" end
track active and archived apartments separately counter_culture :building, column_name: -> { _1.active? ? :apartments_count : :archived_apartments_count } # can do this for the whole account counter_culture %i(building account), column_name: -> { _1.building.active? && _1.active? ? :apartments_count : :arch # can track a sum of a columns counter_culture :building, column_name: :unpaid_taxes_amount, delta_magnitude: -> { _1.unpaid_taxes_amount } counter_culture :building, column_name: :deposit_amount, delta_magnitude: -> { _1.deposit_amount } end
= "#{field_name}_at" model.scope field_name, -> { where(arel_table[column_name].lteq(Time.current)) } model.define_method(:"#{field_name}?") do value = public_send(column_name) value.present? && !value.future? end model.alias_method field_name, "#{field_name}?" model.define_method(:"#{field_name}=") do |value| if value.present? if value.acts_like?(:time) public_send(:"#{column_name}=", value) elsif !public_send(field_name) public_send(:"#{column_name}=", Time.current) end else public_send(:"#{column_name}=", nil) end end if reverse model.scope reverse, -> { where(column_name => nil).or(where(arel_table[column_name].gteq(Time.current))) } model.define_method(:"#{reverse}?") { !public_send(field_name) } else model.scope "not_#{field_name}", -> { where(column_name => nil) } end end end
extension_module.respond_to?(:define) extend(extension_module.const_get(:ClassMethods)) if extension_module.const_defined?(:ClassMethods) include(extension_module.const_get(:InstanceMethods)) if extension_module.const_defined?(:InstanceMethods) end end
when Print::BuildingTemplate then print_template_path(record) when Calendar::Event then event_path(record) when Finance::BulkWithdraw then bulk_withdraw_path(record) when Issues::Type then issue_type_path(record) when Messaging::Bulk then bulk_message_path(record) when Messaging::Message then message_path(record) when MoneyTransfer then transaction_path(record) when PaymentImport::Entry then payment_import_path(record) when Tasks::RecurringTask then recurring_task_path(record) when Tasks::Task then task_path(record) when Taxation::Payment then payment_path(record) when Taxation::PaymentDocument then payment_document_path(record) else url_for(record) end end def record_url(record) #.... end # ... end
end def capture_exception(error) if Rails.env.production? if error.is_a?(String) Sentry.capture_message(error) else Sentry.capture_exception(error) end else raise error end end def exception_context(prop, hash) Sentry.set_context(prop, hash) if Rails.env.production? end def graphql_path(path) exception_context('graphql_info', path: path) end def job_discarded(job, exception) Rails.logger.error "Discarded #{job.class} due to #{exception.cause.inspect}." exception_context('job', name: job.class.name, arguments: job.arguments) capture_exception(exception) end end
rails translate:fill_in_missing_translations 1. Compare all config/locales/[lang].yaml 2. Find missing keys 3. Prompt OpenAI API for translations 4. Add new translations 5. Format YAML (sort keys)
- manage: [url to manage tokens] # - api: [url to api documentation] # - gem: [gem we are using (optional)] # [- ... other links] module External::[Service]Api extend self # documentation: [documentation] def perform_action(args) # use HTTParty or gem for this external service end end
user.admin? || account.member?(user) end end # generates ApplicationPolicy.can_access_account?(user, account) # can be accessed as ApplicationPolicy.can?(user, :access, account) ApplicationPolicy.authorize!(user, :access, account) # raise KittyPolicy::AccessDenied
template: 'system/unauthorized' end end class_methods do def require_account_feature(feature_name) self.required_account_feature = feature_name end end private def find_record(scope, id = :none, authorize: :view) record = scope.find(id == :none ? params[:id] : id) ApplicationPolicy.authorize!(current_user, authorize, record) if self.class.required_account_feature.present? Accounts.feature_available!(record, self.class.required_account_feature) end
scope.find(id == :none ? params[:id] : id) ApplicationPolicy.authorize!(current_user, authorize, record) if self.class.required_account_feature.present? Accounts.feature_available!(record, self.class.required_account_feature) end record end end
record.respond_to?(:account) record.account elsif record.respond_to?(:building) record.building.account else raise "Can't find account for #{record.class}##{record.id}" end end def feature_available?(record, feature_name) account_of(record).features.available?(feature_name) end def feature_available!(record, feature_name) return if feature_available?(record, feature_name) raise FeatureUnavailable.new(record, feature_name) end end
user.admin? || account.member?(user) end end # generates ApplicationPolicy.can_access_account?(user, account) # can be accessed as ApplicationPolicy.can?(user, :access, account) ApplicationPolicy.authorize!(user, :access, account) # raise KittyPolicy::AccessDenied
template: 'system/unauthorized' end end class_methods do def require_account_feature(feature_name) self.required_account_feature = feature_name end end private def find_record(scope, id = :none, authorize: :view) record = scope.find(id == :none ? params[:id] : id) ApplicationPolicy.authorize!(current_user, authorize, record) if self.class.required_account_feature.present? Accounts.feature_available!(record, self.class.required_account_feature) end
scope.find(id == :none ? params[:id] : id) ApplicationPolicy.authorize!(current_user, authorize, record) if self.class.required_account_feature.present? Accounts.feature_available!(record, self.class.required_account_feature) end record end end
record.respond_to?(:account) record.account elsif record.respond_to?(:building) record.building.account else raise "Can't find account for #{record.class}##{record.id}" end end def feature_available?(record, feature_name) account_of(record).features.available?(feature_name) end def feature_available!(record, feature_name) return if feature_available?(record, feature_name) raise FeatureUnavailable.new(record, feature_name) end end