Comments (16)
Personally, I think that the validate
prefix approach is better because such a name will always explain exactly what the method does. It's more important that the method's name is precise than that the validation line reads well.
from rails-style-guide.
To add to @pirj 's excellent summary, I think the method name should have a required prefix, whether it's must_
or validate_
. IMO, it's helpful to easily recognize that the method is a custom validation by the prefix rather than scanning the entire method name to see if it includes must
/validate
.
eg.
# Good
validate :validate_birthday_in_past
validate :validate_owner_has_no_other_items
# Also good
validate :must_have_owner_with_no_other_items
validate :must_have_birthday_in_past
# Bad
validate :birthday_in_past_validation
validate :owner_has_no_other_items_validation
validate :birthday_must_be_in_past
validate :owner_must_not_have_other_items
Then I think the ideal criteria would be
- The name should indicate that the method is a "custom validation", not a predicate method.
- The name causes the
validate :method_name
line to read like a natural statement - The name should reflect what it does on its own
- The method should be instantly recognizable as a validation method.
from rails-style-guide.
Just to expand on my post, methods are what makes up the API that's going to be reused. If I'm scanning through the method list and see something like name_must_be_snake_case
, I don't immediately know what that method does. It could be used for validation but it could also return a boolean that indicates if name
must be snake_case
or not. If that method were called validate_name_is_snake_case
, I'd know at once that it's not something I'd want to reuse for anything other than validation.
from rails-style-guide.
This discussion is very interesting and instructive :-)
I would like to share with you the linter we implemented in our project for that purpose ("validate_" prefix).
# frozen_string_literal: true
module RuboCop
module Cop
# Ensure custom validators to have prefix "validate_"
class UsePrefixForCustomValidator < RuboCop::Cop::Cop
MSG = 'Add a prefix "validate_" to custom validator names'
CUSTOM_VALIDATOR_METHOD = :validate
def on_send(node)
method = method_name(node)
return unless custom_validator_method?(method)
first_argument_node = first_argument(node)
add_offense(first_argument_node, location: :expression) if missing_prefix?(first_argument_node.value)
end
private
def custom_validator_method?(method)
method == CUSTOM_VALIDATOR_METHOD
end
def method_name(node)
node.children[1]
end
def first_argument(node)
node.arguments[0]
end
def missing_prefix?(custom_validator_name)
!custom_validator_name.to_s.start_with?('validate_')
end
end
end
end
from rails-style-guide.
I find that repeating the word "validate" doesn't read well. So I prefer naming them with a phrase containing "must":
validate :must_have_enough_capacity
validate :must_be_enabled
validate :start_date_must_precede_end_date
This helps avoid the above mentioned confusion with methods that return true/false, and also reads as a specification.
from rails-style-guide.
Just like the validate_
prefix naming practice, a good number of open source projects adopt the must
naming practice (see end of comment for examples).
What can we distill from these two practices, without being prescriptive about the verb used? Here's one possible guideline:
Choose names for custom validation methods that capture the method is responsible for validation only. Avoid names which imply the method returns a boolean and/or the method has no side effects.
# bad
class Person < ApplicationRecord
validate :birthday_in_past
# method name misleadingly suggests it returns a boolean and
# has no side effects.
def birthday_in_past
errors.add(:birthday, "must be in past") unless birthday.past?
end
end
# good
class Person < ApplicationRecord
# it is common practice to use a verb like "validate" or "must"
# in custom validation method names
validate :validate_birthday_in_past
# or using "must": validate :birthday_must_be_in_past
def validate_birthday_in_past
errors.add(:birthday, "must be in past") unless birthday.past?
end
end
Feedback encouraged!
Examples of must
naming practice from select open-source projects
$ ag --ruby 'validate .+must'
apps/accelerated_claims/app/models/deposit.rb
15: validate :money_or_property_must_be_selected_if_received
17: validate :information_given_date_must_not_be_invalid
apps/accelerated_claims/app/models/notice.rb
20: validate :expiry_date_must_be_after_served_date
apps/alaveteli/app/models/info_request_event.rb
94: validate :must_be_valid_state
apps/alaveteli/app/models/info_request.rb
72: validate :must_be_internal_or_external
151: validate :must_be_valid_state
apps/askthem/app/models/question.rb
65: validate :state_must_be_included_in_the_list_of_states
66: validate :subject_must_be_included_in_the_list_of_subjects
67: validate :question_and_person_must_belong_to_the_same_jurisdiction
68: validate :person_and_bill_must_belong_to_the_same_jurisdiction
apps/canvas-lms/app/models/access_token.rb
33: validate :must_only_include_valid_scopes, unless: :deleted?
apps/canvas-lms/app/models/discussion_entry.rb
51: validate :must_be_reply_to_same_discussion, on: :create
apps/canvas-lms/app/models/discussion_topic.rb
82: validate :section_specific_topics_must_have_sections
apps/canvas-lms/app/models/pseudonym.rb
37: validate :must_be_root_account
apps/canvas-lms/app/models/role_override.rb
28: validate :must_apply_to_something
apps/catarse/app/models/concerns/contribution/custom_validators.rb
7: validate :reward_must_be_from_project
8: validate :value_must_be_at_least_rewards_value
apps/diaspora/app/models/reshare.rb
9: validate :root_must_be_public
apps/diaspora/app/models/user_preference.rb
6: validate :must_be_valid_email_type
apps/discourse/app/models/embeddable_host.rb
4: validate :host_must_be_valid
apps/foodsoft/app/models/delivery.rb
10: validate :stock_articles_must_be_unique
apps/gitlabhq/app/models/project_label.rb
9: validate :title_must_not_exist_at_group_level
apps/growstuff/app/models/crop.rb
42: validate :must_be_rejected_if_rejected_reasons_present
43: validate :must_have_meaningful_reason_for_rejection
apps/growstuff/app/models/harvest.rb
67: validate :crop_must_match_planting
68: validate :owner_must_match_planting
69: validate :harvest_must_be_after_planting
apps/growstuff/app/models/planting.rb
48: validate :finished_must_be_after_planted
49: validate :owner_must_match_garden_owner
apps/lale-help/app/models/sponsorship.rb
7: validate :ends_on_must_be_before_starts_on
apps/locomotivecms-engine/app/models/locomotive/concerns/content_type/entry_template.rb
13: validate :entry_template_must_be_valid
apps/locomotivecms-engine/app/models/locomotive/concerns/site/access_points.rb
26: validate :domains_must_be_valid_and_unique
27: validate :domains_must_not_be_reserved
28: validate :asset_host_must_be_valid
apps/manageiq/app/models/miq_provision_configured_system_request.rb
6: validate :must_have_user
apps/manageiq/app/models/miq_provision_request.rb
17: validate :must_have_user
apps/manageiq/app/models/miq_retire_request.rb
4: validate :must_have_user
apps/manageiq/app/models/service_reconfigure_request.rb
7: validate :must_have_user
apps/manageiq/app/models/service_template_provision_request.rb
7: validate :must_have_user
apps/manageiq/app/models/vm_migrate_request.rb
7: validate :must_have_user
apps/manageiq/app/models/vm_cloud_reconfigure_request.rb
8: validate :must_have_user
apps/manageiq/app/models/vm_reconfigure_request.rb
7: validate :must_have_user
apps/markus/app/models/student_membership.rb
21: validate :must_be_valid_student
apps/markus/app/models/ta_membership.rb
2: validate :must_be_a_ta
apps/mastodon/app/models/custom_filter.rb
30: validate :context_must_be_valid
31: validate :irreversible_must_be_within_context
apps/metrics/app/models/metric.rb
24: validate :pattern_must_be_valid
25: validate :pattern_must_not_contain_reserved_names, if: :valid_pattern?
26: validate :feedback_must_not_contain_unknown_names, if: :valid_pattern?
apps/radiant/app/models/radiant/config.rb
321: validate :definition_must_be_valid
apps/ror_ecommerce/app/models/inventory.rb
20: validate :must_have_stock
apps/shoppe/app/models/shoppe/stock_level_adjustment.rb
12: validate { errors.add(:adjustment, I18n.t('shoppe.activerecord.attributes.stock_level_adjustment.must_be_greater_or_equal_zero')) if adjustment == 0 }
apps/signonotron2/app/models/bulk_grant_permission_set.rb
8: validate :must_have_at_least_one_supported_permission
apps/solidus/core/app/models/spree/return_authorization.rb
22: validate :must_have_shipped_units, on: :create
apps/spree/core/app/models/spree/customer_return.rb
14: validate :must_have_return_authorization, on: :create
apps/spree/core/app/models/spree/product.rb
104: validate :discontinue_on_must_be_later_than_available_on, if: -> { available_on && discontinue_on }
apps/spree/core/app/models/spree/promotion.rb
27: validate :expires_at_must_be_later_than_starts_at, if: -> { starts_at && expires_at }
apps/spree/core/app/models/spree/return_authorization.rb
22: validate :must_have_shipped_units, on: :create
apps/squash-web/app/models/comment.rb
65: validate :user_must_have_permission_to_comment
apps/squash-web/app/models/email.rb
69: validate :user_must_be_member_of_project
apps/squash-web/app/models/bug.rb
182: validate :open_bugs_cannot_be_deployed, :assigned_user_must_be_project_member,
apps/test_track/app/models/app.rb
8: validate :auth_secret_must_be_sufficiently_strong
apps/test_track/app/models/assignment.rb
14: validate :variant_must_exist
apps/test_track/app/models/bulk_assignment_creation.rb
13: validate :most_identifiers_must_exist
apps/test_track/app/models/identifier_type.rb
6: validate :name_must_be_snake_case
apps/test_track/app/models/identifier_claim.rb
9: validate :identifier_type_must_exist
apps/test_track/app/models/split.rb
12: validate :name_must_be_snake_case
13: validate :name_must_not_include_new
14: validate :name_must_not_end_with_test
15: validate :variants_must_be_snake_case
16: validate :registry_weights_must_sum_to_100
17: validate :registry_weights_must_be_integers
apps/test_track/app/models/split_creation.rb
7: validate :split_must_be_valid
apps/test_track/app/models/variant_detail.rb
6: validate :variant_must_exist
apps/tomatoes/app/models/tomato.rb
14: validate :must_not_overlap, on: :create
apps/uberzeit/app/models/concerns/customer_assignable.rb
9: validate :customer_must_exist
apps/uberzeit/app/models/absence.rb
40: validate :must_not_overlap_with_other_absences
apps/uberzeit/app/models/time_entry.rb
34: validate :must_be_only_timer_on_date, if: :timer?
apps/whitehall/app/models/bulk_upload.rb
18: validate :attachments_must_be_valid
97: validate :must_be_a_zip_file
apps/whitehall/app/models/statistics_announcement_date.rb
9: validate :confirmed_date_must_be_exact
apps/worldcubeassociation.org/WcaOnRails/app/models/competition.rb
156: validate :must_have_at_least_one_event, if: :confirmed_or_visible?
191: validate :must_have_at_least_one_delegate, if: :confirmed_or_visible?
213: validate :delegates_must_be_delegates, unless: :is_probably_over?
314: validate :dates_must_be_valid
416: validate :registration_must_close_after_it_opens
apps/worldcubeassociation.org/WcaOnRails/app/models/merge_people.rb
43: validate :must_look_like_the_same_person
61: validate :person2_must_not_have_associated_user
apps/worldcubeassociation.org/WcaOnRails/app/models/poll.rb
13: validate :must_have_at_least_two_options, if: :confirmed?
apps/worldcubeassociation.org/WcaOnRails/app/models/person.rb
46: validate :dob_must_be_in_the_past
apps/worldcubeassociation.org/WcaOnRails/app/models/registration.rb
26: validate :competition_must_use_wca_registration
212: validate :must_register_for_gte_one_event
apps/worldcubeassociation.org/WcaOnRails/app/models/team_member.rb
15: validate :start_date_must_be_earlier_than_end_date
apps/worldcubeassociation.org/WcaOnRails/app/models/vote.rb
10: validate :poll_id_must_be_valid
17: validate :option_must_match_poll
24: validate :must_have_at_least_one_option
31: validate :number_of_options_must_match_poll
38: validate :poll_must_be_confirmed
45: validate :poll_must_still_be_open
apps/worldcubeassociation.org/WcaOnRails/app/models/user.rb
93: validate :name_must_match_person_name
100: validate :dob_must_be_in_the_past
287: validate :senior_delegate_must_be_senior_delegate
apps/worldcubeassociation.org/WcaOnRails/lib/solve_time.rb
257: validate :times_over_10_minutes_must_be_rounded
from rails-style-guide.
Let's look at the Rails' guide:
validate :expiration_date_cannot_be_in_the_past,
:discount_cannot_be_greater_than_total_value
validate :active_customer, on: :create
def expiration_date_cannot_be_in_the_past
if expiration_date.present? && expiration_date < Date.today
errors.add(:expiration_date, "can't be in the past")
end
end
I can see the following reasons for having a naming guideline for custom validators:
- indicate that a method is used in validations and is not intended to be used as a predicate
- make
validate :...
to read like a correct statement - make method name on its own to reflect what it does
Is there a clear way how to hit all three goals at once? Quite unlikely from my point of view, even considering that predicate methods usually end with ?
.
Prefixing with validate_
at least solves 1 & 3.
from rails-style-guide.
Don't forget you could completely skip this discussion if you write a custom validator.
validates :birthday, in_past: true
This might not always be the best option, but for more general things like checking if a date is in the past it's a pretty logical choice.
from rails-style-guide.
In my opinion, it's all down to having a convention. If I see X, and I know X is what we call custom validations, then it's clear no matter what X is. If there's no convention, neither "validate", nor "must" would tell me enough: validate_name_is_snake_case
— is it just a boolean telling me whether to perform the validation or the validation itself?
So the important part that I see is to pick something that allows to easily express the intention.
Besides naming, we can also reduce the risk by keeping the validation methods private, putting them all consecutively together, maybe with a comment to separate the section of code. This should make it fool-proof.
from rails-style-guide.
I prefer the must
prefix, because it makes the validate line more readable and less prolix
Let's look at both sentences
1
validate :name_must_be_in_the_past
# Validates name must be in the past
2
validate :validate_name_is_in_the_past
# Validates validates name is in the past
The first sentence makes much more sense
from rails-style-guide.
I try to follow this guidance.
Consider adding a line in the validate_
method that shows what the custom validation could look like, as a common mistake is for these methods to be written to return a boolean rather than add to the errors
object - as you say in the comments in email_is_not_gmail_account
.
from rails-style-guide.
This guidance is followed in a few open source projects, examples follow:
apps/24pullrequests/app/models/event.rb
5: validate :validate_start_time_is_in_range, if: :start_time
6: validate :validate_start_time_is_not_in_the_past, if: :start_time
apps/accelerated_claims/app/models/claimant.rb
17: validate :validate_claimant_state
apps/accelerated_claims/app/models/defendant.rb
20: validate :validate_defendant_state
apps/accelerated_claims/app/models/notice.rb
4: validate :validate_notice_served
apps/accelerated_claims/app/models/tenancy.rb
68: t.validate :validate_applicable_statements_confirmed
apps/alchemy_cms/lib/alchemy/essence.rb
36: validate :validate_ingredient, :on => :update, :if => 'validations.any?'
apps/bridge_troll/app/models/event.rb
90: validate :validate_student_rsvp_limit
99: validate :validate_volunteer_rsvp_limit
apps/canvas-lms/app/models/account.rb
127: validate :validate_auth_discovery_url
apps/canvas-lms/app/models/account_authorization_config.rb
83: validate :validate_federated_attributes
apps/canvas-lms/app/models/account_notification.rb
20: validate :validate_dates
apps/canvas-lms/app/models/communication_channel.rb
38: validate :validate_email, if: lambda { |cc| cc.path_type == TYPE_EMAIL && cc.new_record? }
apps/canvas-lms/app/models/course_section.rb
42: validate :validate_section_dates
apps/canvas-lms/app/models/course.rb
212: validate :validate_course_dates
213: validate :validate_course_image
apps/canvas-lms/app/models/developer_key.rb
40: validate :validate_redirect_uris
apps/canvas-lms/app/models/discussion_entry.rb
49: validate :validate_depth, on: :create
apps/canvas-lms/app/models/discussion_topic.rb
75: validate :validate_draft_state_change, :if => :workflow_state_changed?
apps/canvas-lms/app/models/group_membership.rb
29: validate :validate_within_group_limit
apps/canvas-lms/app/models/learning_outcome.rb
55: validate :validate_calculation_int
56: validate :validate_text_only_changes_when_assessed
apps/canvas-lms/app/models/quizzes/quiz.rb
54: validate :validate_quiz_type, :if => :quiz_type_changed?
55: validate :validate_ip_filter, :if => :ip_filter_changed?
56: validate :validate_hide_results, :if => :hide_results_changed?
57: validate :validate_correct_answer_visibility, :if => lambda { |quiz|
apps/canvas-lms/app/models/wiki_page.rb
52: validate :validate_front_page_visibility
apps/canvas-lms/lib/canvas/draft_state_validations.rb
22: validate :validate_draft_state_change, :if => :workflow_state_changed?
apps/cartodb/app/models/carto/analysis.rb
13: validate :validate_user_not_viewer
apps/cartodb/app/models/carto/asset.rb
19: validate :validate_storage_info, if: :storage_info
apps/cartodb/app/models/carto/data_import.rb
31: validate :validate_collision_strategy
apps/cartodb/app/models/carto/layer.rb
90: validate :validate_not_viewer
apps/cartodb/app/models/carto/map.rb
44: validate :validate_options
apps/cartodb/app/models/carto/overlay.rb
14: validate :validate_user_not_viewer
apps/cartodb/app/models/carto/user_table.rb
45: validate :validate_user_not_viewer
49: validate :validate_privacy_changes
apps/cartodb/app/models/carto/visualization.rb
90: validate :validate_password_presence
91: validate :validate_privacy_changes
92: validate :validate_user_not_viewer, on: :create
apps/cartodb/app/models/carto/widget.rb
19: validate :validate_user_not_viewer
apps/case_file_editor/app/models/compensation_application.rb
50: validate :validate_defendant_names
apps/case_file_editor/app/models/domestic_violence.rb
17: validate :validate_victim_name
apps/case_file_editor/app/models/concerns/property_id_validation.rb
12: validate :validate_property_ids
apps/case_file_editor/app/models/defendant.rb
436: validate :validate_by_age
apps/case_file_editor/app/models/mme_recorded_response.rb
42: validate :validate_id
apps/case_file_editor/app/models/mme_not_recorded_response.rb
15: validate :validate_no_mme_not_recorded_if_mme_present
apps/case_file_editor/app/models/mme.rb
55: validate :validate_id_uniqueness
apps/case_file_editor/app/models/property.rb
53: validate :validate_id_uniqueness
apps/case_file_editor/app/models/witness.rb
66: validate :validate_id_uniqueness, if: :witness_id
apps/catarse/app/models/concerns/project/custom_validators.rb
11: validate :validate_tags
apps/cloudnet/app/models/server_wizard.rb
33: validate :validate_wallet_credit, if: :step3?
34: validate :validate_provisioner_template, if: :step2?
apps/coursemology2/app/models/concerns/announcement_concern.rb
12: validate :validate_start_at_cannot_be_after_end_at
apps/coursemology2/app/models/course/assessment/answer/programming_file.rb
8: validate :validate_content_size
apps/coursemology2/app/models/course/assessment/answer/text_response.rb
8: validate :validate_filenames_are_unique, if: :attachments_changed?
apps/coursemology2/app/models/course/assessment/answer.rb
36: validate :validate_consistent_assessment
37: validate :validate_assessment_state, if: :attempting?
41: validate :validate_grade, unless: :attempting?
apps/coursemology2/app/models/course/assessment/question/multiple_response.rb
7: validate :validate_multiple_choice_has_solution, if: :multiple_choice?
apps/coursemology2/app/models/course/assessment/question/text_response.rb
5: validate :validate_grade
apps/coursemology2/app/models/course/assessment/question/text_response_solution.rb
6: validate :validate_grade
apps/coursemology2/app/models/course/assessment/skill.rb
7: validate :validate_consistent_course
apps/coursemology2/app/models/course/condition/achievement.rb
15: validate :validate_achievement_condition, if: :achievement_id_changed?
apps/coursemology2/app/models/course/condition/assessment.rb
12: validate :validate_assessment_condition, if: :assessment_id_changed?
apps/coursemology2/app/models/course/assessment/submission.rb
33: validate :validate_consistent_user, :validate_unique_submission, on: :create
34: validate :validate_awarded_attributes, if: :published?
apps/coursemology2/app/models/course/enrol_request.rb
3: validate :validate_user_not_in_course, on: :create
apps/coursemology2/app/models/course/group.rb
15: validate :validate_new_users_are_unique
16: validate :validate_presence_of_group_manager, on: :update
apps/coursemology2/app/models/course/lesson_plan/item.rb
10: validate :validate_presence_of_bonus_end_at,
apps/coursemology2/app/models/course/material.rb
10: validate :validate_name_is_unique_among_folders
apps/coursemology2/app/models/course/material/folder.rb
16: validate :validate_name_is_unique_among_materials
apps/coursemology2/app/models/course/video/session.rb
8: validate :validate_start_before_end
apps/coursemology2/app/models/course/video/submission.rb
10: validate :validate_consistent_user, :validate_unique_submission, on: :create
apps/diaspora/app/models/api/openid_connect/authorization.rb
11: validate :validate_scope_names
apps/ds-auth/app/models/application_membership.rb
6: validate :validate_application_available_to_user
apps/e-petitions/app/models/archived/debate_outcome.rb
25: validate :validate_commons_image_dimensions, unless: :no_commons_image_queued
apps/e-petitions/app/models/debate_outcome.rb
22: validate :validate_commons_image_dimensions, unless: :no_commons_image_queued
apps/errbit/app/models/issue_tracker.rb
10: validate :validate_tracker
apps/foreman/app/models/auth_sources/auth_source_ldap.rb
38: validate :validate_ldap_filter, :unless => Proc.new { |auth| auth.ldap_filter.blank? }
apps/foreman/app/models/concerns/hostext/ownership.rb
14: validate :validate_owner
apps/foreman/app/models/concerns/parameter_validators.rb
6: validate :validate_parameters_names
apps/foreman/app/models/concerns/pxe_loader_validator.rb
5: validate :validate_pxe_loader
apps/foreman/app/models/concerns/user_time.rb
5: validate :validate_timezone
apps/foreman/app/models/hostgroup.rb
13: validate :validate_subnet_types
apps/foreman/app/models/lookup_keys/variable_lookup_key.rb
7: validate :validate_default_value, :disable_merge_overrides, :disable_avoid_duplicates, :disable_merge_default
apps/foreman/app/models/lookup_value.rb
16: validate :validate_value, :unless => Proc.new{|p| p.omit }
apps/foreman/app/models/lookup_keys/puppetclass_lookup_key.rb
8: validate :validate_default_value, :disable_merge_overrides, :disable_avoid_duplicates, :disable_merge_default, :if => :override?
apps/foreman/app/models/nic/bmc.rb
8: validate :validate_bmc_proxy
apps/foreman/app/models/nic/base.rb
21: validate :validate_mac_is_unicast,
37: validate :validate_subnet_types
apps/foreman/app/models/setting.rb
45: validate :validate_host_owner, :if => Proc.new {|s| s.name == "host_owner" }
55: validate :validate_frozen_attributes
apps/foreman/app/models/subnet/ipv6.rb
11: validate :validate_eui64_prefix_length, :if => Proc.new { |subnet| subnet.ipam == IPAM::MODES[:eui64]}
apps/foreman/app/models/subnet.rb
76: validate :validate_ranges
apps/gitlabhq/app/models/merge_request.rb
98: validate :validate_branches, unless: [:allow_broken, :importing?, :closed_without_fork?]
99: validate :validate_fork, unless: :closed_without_fork?
100: validate :validate_target_project, on: :create
apps/gitlabhq/app/models/pages_domain.rb
9: validate :validate_pages_domain
10: validate :validate_matching_key, if: ->(domain) { domain.certificate.present? || domain.key.present? }
11: validate :validate_intermediates, if: ->(domain) { domain.certificate.present? }
apps/gitlabhq/app/models/personal_access_token.rb
18: validate :validate_scopes
apps/hours/app/models/signup.rb
13: validate :validate_children
apps/huginn/app/concerns/email_concern.rb
7: self.validate :validate_email_options
apps/huginn/app/concerns/agent_controller_concern.rb
5: validate :validate_control_action
apps/huginn/app/concerns/assignable_types.rb
5: validate :validate_type
apps/huginn/app/concerns/evernote_concern.rb
7: validate :validate_evernote_options
apps/huginn/app/concerns/sortable_events.rb
5: validate :validate_events_order
apps/huginn/app/concerns/liquid_interpolatable.rb
7: validate :validate_interpolation
apps/huginn/app/concerns/twitter_concern.rb
7: validate :validate_twitter_options
apps/huginn/app/concerns/weibo_concern.rb
7: self.validate :validate_weibo_options
apps/huginn/app/importers/scenario_import.rb
20: validate :validate_presence_of_file_url_or_data
22: validate :validate_data
apps/huginn/app/models/agent.rb
36: validate :validate_schedule
37: validate :validate_options
apps/jobsworth/app/models/abstract_task.rb
63: validate :validate_properties
apps/jobsworth/app/models/custom_attribute_value.rb
6: validate :validate_custom_attribute
apps/jobsworth/app/models/customer.rb
33: validate :validate_custom_attributes
apps/jobsworth/app/models/organizational_unit.rb
13: validate :validate_custom_attributes
apps/jobsworth/app/models/resource.rb
21: validate :validate_attributes
apps/jobsworth/app/models/user.rb
78: validate :validate_custom_attributes
apps/jobsworth/app/models/work_log.rb
32: validate :validate_logs
apps/katello/app/models/katello/content_view_filter.rb
22: validate :validate_content_view
23: validate :validate_repos
apps/katello/app/models/katello/event.rb
3: validate :validate_event_type
apps/katello/app/models/katello/host_collection_hosts.rb
6: validate :validate_max_hosts_not_exceeded
apps/katello/app/models/katello/sync_plan.rb
23: validate :validate_sync_date
apps/locomotivecms-engine/app/models/locomotive/concerns/site/metafields.rb
16: validate :validate_metafields_schema
apps/loomio/app/models/concerns/group_privacy.rb
10: validate :validate_parent_members_can_see_discussions
11: validate :validate_is_visible_to_parent_members
12: validate :validate_discussion_privacy_options
apps/loomio/app/models/membership_request.rb
5: validate :validate_not_in_group_already
6: validate :validate_unique_membership_request
apps/manageiq/app/models/classification.rb
24: validate :validate_format_of_name
26: validate :validate_uniqueness_on_tag_name
apps/manageiq/app/models/dialog.rb
8: validate :validate_children
apps/manageiq/app/models/dialog_group.rb
5: validate :validate_children
apps/manageiq/app/models/dialog_tab.rb
5: validate :validate_children
apps/manageiq/app/models/endpoint.rb
10: validate :validate_certificate_authority
apps/manageiq/app/models/miq_alert.rb
9: validate :validate_automate_expressions
apps/manageiq/app/models/miq_group.rb
23: validate :validate_default_tenant, :on => :update, :if => :tenant_id_changed?
apps/manageiq/app/models/miq_request.rb
29: validate :validate_class, :validate_request_type
apps/manageiq/app/models/service_reconfigure_task.rb
2: validate :validate_request_type, :validate_state
apps/manageiq/app/models/service_template_provision_task.rb
2: validate :validate_request_type, :validate_state
apps/manageiq/app/models/tenant.rb
45: validate :validate_default_tenant, :on => :update, :if => :default_miq_group_id_changed?
apps/manageiq/app/models/vm_migrate_task.rb
4: validate :validate_request_type, :validate_state
apps/manageiq/app/models/vm_reconfigure_task.rb
4: validate :validate_request_type, :validate_state
apps/netguru-people/app/models/membership.rb
12: validate :validate_starts_at_ends_at
13: validate :validate_duplicate_project
apps/onebody/app/models/custom_field_value.rb
10: validate :validate_value_format
apps/onebody/app/models/friendship_request.rb
11: validate :validate_email_on_target
17: validate :validate_friends_enabled_on_target
apps/onebody/app/models/group.rb
51: validate :validate_self_referencing_parents_of
59: validate :validate_attendance_enabled_for_checkin_destinations
apps/onebody/app/models/membership.rb
22: validate :validate_roles
apps/onebody/app/models/membership_request.rb
16: validate :validate_duplicate_membership
apps/onebody/app/models/person.rb
69: validate :validate_password_length
70: validate :validate_password_strength
107: validate :validate_email_unique
apps/onebody/app/models/signup.rb
13: validate :validate_adult
14: validate :validate_not_a_bot
15: validate :validate_sign_up_allowed
apps/onebody/app/models/verification.rb
13: validate :validate_max_attempts, on: :create
14: validate :validate_people, if: -> { email || mobile_phone }
15: validate :validate_people_able_to_sign_in, if: -> { email || mobile_phone }
apps/open-build-service/src/api/app/models/attrib.rb
34: validate :validate_value_count,
apps/open-build-service/src/api/app/models/comment.rb
10: validate :validate_parent_id
apps/open-build-service/src/api/app/models/flag.rb
20: validate :validate_custom_save
27: validate :validate_duplicates, on: :create
apps/open-build-service/src/api/app/models/groups_user.rb
7: validate :validate_duplicates
11: validate :validate_duplicates, on: :create
apps/open-build-service/src/api/app/models/group_maintainer.rb
7: validate :validate_duplicates
11: validate :validate_duplicates, on: :create
apps/open-build-service/src/api/app/models/linked_project.rb
5: validate :validate_duplicates
apps/open-build-service/src/api/app/models/review.rb
22: validate :validate_non_symmetric_assignment
23: validate :validate_not_self_assigned
apps/openproject/app/models/custom_field.rb
58: validate :validate_default_value
59: validate :validate_regex
apps/openproject/app/models/custom_value.rb
35: validate :validate_presence_of_required_value
36: validate :validate_format_of_value
37: validate :validate_type_of_value
38: validate :validate_length_of_value
apps/openproject/app/models/message.rb
83: validate :validate_unlocked_root, on: :create
apps/openproject/app/models/member_role.rb
38: validate :validate_project_member_role
apps/openproject/app/models/member.rb
40: validate :validate_presence_of_role
41: validate :validate_presence_of_principal
apps/openproject/app/models/queries/filters/base.rb
117: validate :validate_inclusion_of_operator,
apps/openproject/app/models/query.rb
47: validate :validate_work_package_filters
48: validate :validate_columns
49: validate :validate_sort_criteria
50: validate :validate_group_by
51: validate :validate_show_hierarchies
apps/openproject/app/models/relation.rb
96: validate :validate_sanity_of_relation,
apps/openproject/app/models/repository.rb
50: validate :validate_enabled_scm, on: :create
apps/openproject/app/models/system_user.rb
35: validate :validate_unique_system_user, on: :create
apps/openproject/app/models/time_entry.rb
52: validate :validate_hours_are_in_range
53: validate :validate_project_is_set
54: validate :validate_consistency_of_work_package_id
apps/openproject/app/models/type/attribute_groups.rb
34: validate :validate_attribute_group_names
35: validate :validate_attribute_groups
apps/openproject/app/models/timeline.rb
53: validate :validate_option_dates
54: validate :validate_option_numeric
apps/openproject/app/models/user.rb
846: validate :validate_unique_anonymous_user, on: :create
874: validate :validate_unique_deleted_user, on: :create
apps/openproject/app/models/watcher.rb
37: validate :validate_active_user
38: validate :validate_user_allowed_to_watch
apps/openproject/app/models/version.rb
52: validate :validate_start_date_before_effective_date
apps/openproject/app/models/wiki_page.rb
62: validate :validate_consistency_of_parent_title
63: validate :validate_non_circular_dependency
64: validate :validate_same_project
apps/openproject/app/models/work_package/validations.rb
51: validate :validate_start_date_before_soonest_start_date
52: validate :validate_fixed_version_is_assignable, unless: :skip_fixed_version_validation?
53: validate :validate_fixed_version_is_still_open, unless: :skip_fixed_version_validation?
54: validate :validate_enabled_type
56: validate :validate_milestone_constraint
57: validate :validate_parent_constraint
59: validate :validate_status_transition
61: validate :validate_active_priority
63: validate :validate_category
65: validate :validate_descendants, unless: :skip_descendants_validation
67: validate :validate_estimated_hours
apps/openproject/lib/open_project/nested_set/root_id_handling.rb
59: validate :validate_correct_parent
apps/openproject/lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb
50: validate :validate_custom_values
apps/openstreetmap-website/app/models/node.rb
40: validate :validate_position
apps/openstreetmap-website/app/models/note.rb
12: validate :validate_position
apps/openstreetmap-website/app/models/old_node.rb
21: validate :validate_position
apps/planningalerts/app/models/alert.rb
5: validate :validate_address
apps/postal/app/models/additional_route_endpoint.rb
18: validate :validate_endpoint_belongs_to_server
19: validate :validate_wildcard
20: validate :validate_uniqueness
apps/postal/app/models/ip_pool_rule.rb
23: validate :validate_from_and_to_addresses
24: validate :validate_ip_pool_belongs_to_organization
apps/postal/app/models/organization_user.rb
19: validate :validate_uniqueness
apps/postal/app/models/route.rb
41: validate :validate_route_is_routed
42: validate :validate_domain_belongs_to_server
43: validate :validate_endpoint_belongs_to_server
44: validate :validate_name_uniqueness
45: validate :validate_return_path_route_endpoints
46: validate :validate_no_additional_routes_on_non_endpoint_route
apps/postal/app/models/server.rb
78: validate :validate_ip_pool_belongs_to_organization
apps/postal/app/models/track_domain.rb
32: validate :validate_domain_belongs_to_server
apps/prison-visits/app/models/feedback.rb
11: validate :validate_email, if: ->(f) { f.email.present? }
apps/prison-visits/app/models/concerns/person.rb
18: validate :validate_four_digit_year
apps/prison-visits/app/models/confirmation.rb
25: validate :validate_outcome
26: validate :validate_reference
27: validate :validate_renewals
28: validate :validate_unlisted_visitors
29: validate :validate_banned_visitors
apps/prison-visits/app/models/visit.rb
19: validate :validate_amount_of_adults, on: :visitors_set
apps/prison-visits/app/models/visitor.rb
17: validate :validate_email, if: :primary?
apps/publisher/app/models/artefact.rb
117: validate :validate_prefixes_and_paths
apps/redmine/app/models/auth_source_ldap.rb
36: validate :validate_filter
apps/redmine/app/models/attachment.rb
30: validate :validate_max_file_size, :validate_file_extension
apps/redmine/app/models/board.rb
30: validate :validate_board
apps/redmine/app/models/custom_field.rb
37: validate :validate_custom_field
apps/redmine/app/models/group_builtin.rb
19: validate :validate_uniqueness, :on => :create
apps/redmine/app/models/issue.rb
71: validate :validate_issue, :validate_required_fields, :validate_permissions
apps/redmine/app/models/issue_relation.rb
73: validate :validate_issue_relation
apps/redmine/app/models/member.rb
27: validate :validate_role
apps/redmine/app/models/principal.rb
37: validate :validate_status
apps/redmine/app/models/member_role.rb
28: validate :validate_role_member
apps/redmine/app/models/project.rb
79: validate :validate_parent
apps/redmine/app/models/query.rb
220: validate :validate_query_filters
apps/redmine/app/models/repository.rb
50: validate :validate_repository_path
apps/redmine/app/models/time_entry.rb
49: validate :validate_time_entry
apps/redmine/app/models/user.rb
113: validate :validate_password_length
923: validate :validate_anonymous_uniqueness, :on => :create
apps/redmine/app/models/watcher.rb
24: validate :validate_user
apps/redmine/app/models/wiki_page.rb
51: validate :validate_parent_title
apps/redmine/app/models/workflow_permission.rb
21: validate :validate_field_name
apps/redmine/lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb
37: validate :validate_custom_field_values
apps/reservations/app/models/announcement.rb
6: validate :validate_end_date_before_start_date
apps/reservations/app/models/blackout.rb
11: validate :validate_end_date_before_start_date
apps/ror_ecommerce/app/models/image.rb
33: validate :validate_photo
apps/ror_ecommerce/app/models/referral.rb
15: validate :validate_has_not_signed_up_yet
apps/samson/app/models/build.rb
20: validate :validate_git_reference, on: :create
apps/samson/app/models/concerns/permalinkable.rb
8: validate :validate_unique_permalink
apps/samson/app/models/deploy_group.rb
20: validate :validate_vault_server_has_same_environment
apps/samson/app/models/deploy.rb
14: validate :validate_stage_is_unlocked, on: :create
15: validate :validate_stage_uses_deploy_groups_properly, on: :create
apps/samson/app/models/job.rb
14: validate :validate_globally_unlocked
apps/samson/app/models/project.rb
11: validate :validate_can_release
apps/samson/app/models/stage.rb
35: validate :validate_deploy_group_selected
apps/samson/lib/samson/secrets/vault_server.rb
46: validate :validate_cert
47: validate :validate_connection
apps/samson/plugins/env/app/models/concerns/accepts_environment_variables.rb
9: validate :validate_unique_environment_variables
apps/samson/plugins/kubernetes/app/decorators/stage_decorator.rb
3: validate :validate_deploy_groups_have_a_cluster, if: :kubernetes
apps/samson/plugins/kubernetes/app/models/kubernetes/cluster_deploy_group.rb
12: validate :validate_namespace_exists
apps/samson/plugins/kubernetes/app/models/kubernetes/release_doc.rb
16: validate :validate_config_file, on: :create
apps/samson/plugins/kubernetes/app/models/kubernetes/release.rb
14: validate :validate_docker_image_in_registry, on: :create
apps/samson/plugins/slack_webhooks/app/models/slack_webhook.rb
4: validate :validate_url
5: validate :validate_used
apps/scumblr/app/models/task.rb
34: validate :validate_search
apps/signonotron2/app/models/event_log.rb
52: validate :validate_event_mappable
apps/signonotron2/lib/devise/models/password_archivable.rb
18: validate :validate_password_archive
apps/solidus/core/app/models/spree/reimbursement.rb
14: validate :validate_return_items_belong_to_same_order
apps/solidus/core/app/models/spree/return_item.rb
42: validate :validate_acceptance_status_for_reimbursement
44: validate :validate_no_other_completed_return_items
apps/spree/core/app/models/spree/reimbursement.rb
20: validate :validate_return_items_belong_to_same_order
apps/spree/core/app/models/spree/return_item.rb
37: validate :validate_acceptance_status_for_reimbursement
39: validate :validate_no_other_completed_return_items, on: :create
apps/tracks/app/models/user.rb
108: validate :validate_auth_type
apps/verboice/app/models/external_service_step.rb
32: validate :validate_variables
apps/verboice/app/models/schedule.rb
31: validate :validate_retries
apps/whitehall/app/models/consultation.rb
14: validate :validate_closes_after_opens
apps/whitehall/app/models/historical_account.rb
11: validate :validate_correct_political_party
apps/wiki_edu_dashboard/app/models/campaign.rb
43: validate :validate_dates
apps/worldcubeassociation.org/WcaOnRails/app/models/result.rb
24: validate :validate_each_solve, if: :event
33: validate :validate_solve_count, if: :event
41: validate :validate_average
49: validate :validate_best, if: :event
engines/blazer/app/models/blazer/check.rb
7: validate :validate_emails
8: validate :validate_variables, if: -> { query_id_changed? }
engines/thredded/app/forms/thredded/topic_form.rb
10: validate :validate_children
engines/thredded/app/forms/thredded/private_topic_form.rb
22: validate :validate_children
engines/thredded/app/forms/thredded/user_preferences_form.rb
10: validate :validate_children
engines/tolk/app/models/tolk/translation.rb
9: validate :validate_text_not_nil, :if => proc {|r| r.primary.blank? && !r.explicit_nil && !r.boolean?}
from rails-style-guide.
Thanks for the list of repos! I don't think adding a sample implementation would help in the description though as I think that might confuse the reader. 👍
from rails-style-guide.
Yep fair enough I can see that being a distraction
from rails-style-guide.
Has there been any progress here? If not, I'd be happy to write a rule!
from rails-style-guide.
@yjukaku Would you like to send a pull request and add this as a guideline?
from rails-style-guide.
Related Issues (20)
- 7 Standard Controller Actions HOT 11
- Use more specific predicates instead of vague `blank?` and `present?` HOT 2
- Per attribute validations
- Prefer `ActionDispatch::IntegrationTest` over `ActionController::TestCase`
- Better docs for `dependent: :destroy` HOT 1
- Where with Ranges: "good" vs "bad" are not equivalent HOT 3
- Description of Single Attribute Validations seems wrong. HOT 1
- Suggestion: Avoid `render ... and return` HOT 4
- Suggestion: Use string literals instead of named routes or URL helpers in tests HOT 2
- Add delete_all to the list of methods that skip model validations HOT 2
- Cop idea: prefer symbol proc to `if:` and `unless:` filter lambdas HOT 2
- Are blank routes preferred or routes with `/`
- Suggestion: Add notes about `.none()` HOT 1
- Suggestion: Add notes about returned value of ActiveRecord transaction
- Suggestion: Add description about Active Record redundant `all` HOT 1
- Suggestion: don't divide `.where.not` into two lines
- Suggestion: 3-state booleans don't require a default HOT 3
- "Redundant `all`" is too naive HOT 10
- Cop idea: merge `.first` || `.create!` into `.first_or_create!` HOT 6
- Cop idea: Prefer `assert_raises` over `assert_raise` HOT 10
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rails-style-guide.