Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2412ddf03d
commit
42263d6451
15 changed files with 164 additions and 100 deletions
|
@ -1,16 +1,27 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module ResourceEventTools
|
class ResourceEvent < ApplicationRecord
|
||||||
extend ActiveSupport::Concern
|
include Gitlab::Utils::StrongMemoize
|
||||||
|
include Importable
|
||||||
|
|
||||||
included do
|
self.abstract_class = true
|
||||||
belongs_to :user
|
|
||||||
|
|
||||||
validates :user, presence: { unless: :importing? }, on: :create
|
validates :user, presence: { unless: :importing? }, on: :create
|
||||||
|
|
||||||
validate :exactly_one_issuable
|
belongs_to :user
|
||||||
|
|
||||||
scope :created_after, ->(time) { where('created_at > ?', time) }
|
scope :created_after, ->(time) { where('created_at > ?', time) }
|
||||||
|
|
||||||
|
def discussion_id
|
||||||
|
strong_memoize(:discussion_id) do
|
||||||
|
Digest::SHA1.hexdigest(discussion_id_key.join("-"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def discussion_id_key
|
||||||
|
[self.class.name, created_at, user_id]
|
||||||
end
|
end
|
||||||
|
|
||||||
def exactly_one_issuable
|
def exactly_one_issuable
|
|
@ -1,10 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ResourceLabelEvent < ApplicationRecord
|
class ResourceLabelEvent < ResourceEvent
|
||||||
include Importable
|
|
||||||
include Gitlab::Utils::StrongMemoize
|
|
||||||
include CacheMarkdownField
|
include CacheMarkdownField
|
||||||
include ResourceEventTools
|
|
||||||
|
|
||||||
cache_markdown_field :reference
|
cache_markdown_field :reference
|
||||||
|
|
||||||
|
@ -13,8 +10,11 @@ class ResourceLabelEvent < ApplicationRecord
|
||||||
belongs_to :label
|
belongs_to :label
|
||||||
|
|
||||||
scope :inc_relations, -> { includes(:label, :user) }
|
scope :inc_relations, -> { includes(:label, :user) }
|
||||||
|
scope :by_issue, ->(issue) { where(issue_id: issue.id) }
|
||||||
|
scope :by_merge_request, ->(merge_request) { where(merge_request_id: merge_request.id) }
|
||||||
|
|
||||||
validates :label, presence: { unless: :importing? }, on: :create
|
validates :label, presence: { unless: :importing? }, on: :create
|
||||||
|
validate :exactly_one_issuable
|
||||||
|
|
||||||
after_save :expire_etag_cache
|
after_save :expire_etag_cache
|
||||||
after_destroy :expire_etag_cache
|
after_destroy :expire_etag_cache
|
||||||
|
@ -41,12 +41,6 @@ class ResourceLabelEvent < ApplicationRecord
|
||||||
issue || merge_request
|
issue || merge_request
|
||||||
end
|
end
|
||||||
|
|
||||||
def discussion_id(resource = nil)
|
|
||||||
strong_memoize(:discussion_id) do
|
|
||||||
Digest::SHA1.hexdigest(discussion_id_key.join("-"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def project
|
def project
|
||||||
issuable.project
|
issuable.project
|
||||||
end
|
end
|
||||||
|
@ -109,10 +103,6 @@ class ResourceLabelEvent < ApplicationRecord
|
||||||
def resource_parent
|
def resource_parent
|
||||||
issuable.project || issuable.group
|
issuable.project || issuable.group
|
||||||
end
|
end
|
||||||
|
|
||||||
def discussion_id_key
|
|
||||||
[self.class.name, created_at, user_id]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
ResourceLabelEvent.prepend_if_ee('EE::ResourceLabelEvent')
|
ResourceLabelEvent.prepend_if_ee('EE::ResourceLabelEvent')
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ResourceMilestoneEvent < ApplicationRecord
|
class ResourceMilestoneEvent < ResourceEvent
|
||||||
include Gitlab::Utils::StrongMemoize
|
|
||||||
include Importable
|
|
||||||
include ResourceEventTools
|
|
||||||
|
|
||||||
belongs_to :issue
|
belongs_to :issue
|
||||||
belongs_to :merge_request
|
belongs_to :merge_request
|
||||||
belongs_to :milestone
|
belongs_to :milestone
|
||||||
|
@ -12,6 +8,8 @@ class ResourceMilestoneEvent < ApplicationRecord
|
||||||
scope :by_issue, ->(issue) { where(issue_id: issue.id) }
|
scope :by_issue, ->(issue) { where(issue_id: issue.id) }
|
||||||
scope :by_merge_request, ->(merge_request) { where(merge_request_id: merge_request.id) }
|
scope :by_merge_request, ->(merge_request) { where(merge_request_id: merge_request.id) }
|
||||||
|
|
||||||
|
validate :exactly_one_issuable
|
||||||
|
|
||||||
enum action: {
|
enum action: {
|
||||||
add: 1,
|
add: 1,
|
||||||
remove: 2
|
remove: 2
|
||||||
|
@ -23,8 +21,4 @@ class ResourceMilestoneEvent < ApplicationRecord
|
||||||
def self.issuable_attrs
|
def self.issuable_attrs
|
||||||
%i(issue merge_request).freeze
|
%i(issue merge_request).freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource
|
|
||||||
issue || merge_request
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,26 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ResourceWeightEvent < ApplicationRecord
|
class ResourceWeightEvent < ResourceEvent
|
||||||
include Gitlab::Utils::StrongMemoize
|
|
||||||
|
|
||||||
validates :user, presence: true
|
|
||||||
validates :issue, presence: true
|
validates :issue, presence: true
|
||||||
|
|
||||||
belongs_to :user
|
|
||||||
belongs_to :issue
|
belongs_to :issue
|
||||||
|
|
||||||
scope :by_issue, ->(issue) { where(issue_id: issue.id) }
|
scope :by_issue, ->(issue) { where(issue_id: issue.id) }
|
||||||
scope :created_after, ->(time) { where('created_at > ?', time) }
|
|
||||||
|
|
||||||
def discussion_id(resource = nil)
|
|
||||||
strong_memoize(:discussion_id) do
|
|
||||||
Digest::SHA1.hexdigest(discussion_id_key.join("-"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def discussion_id_key
|
|
||||||
[self.class.name, created_at, user_id]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Improve error messages of failed migrations
|
||||||
|
merge_request: 25457
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -122,7 +122,7 @@ Parameters:
|
||||||
| `userName` | string | yes | Username of the user. |
|
| `userName` | string | yes | Username of the user. |
|
||||||
| `emails` | JSON string | yes | Work email. |
|
| `emails` | JSON string | yes | Work email. |
|
||||||
| `name` | JSON string | yes | Name of the user. |
|
| `name` | JSON string | yes | Name of the user. |
|
||||||
| `meta` | string | no | Resource type (`User'). |
|
| `meta` | string | no | Resource type (`User`). |
|
||||||
|
|
||||||
Example request:
|
Example request:
|
||||||
|
|
||||||
|
|
|
@ -571,9 +571,12 @@ Below you can find supported syntax reference:
|
||||||
- `$VARIABLE =~ /^content.*/`
|
- `$VARIABLE =~ /^content.*/`
|
||||||
- `$VARIABLE_1 !~ /^content.*/` (introduced in GitLab 11.11)
|
- `$VARIABLE_1 !~ /^content.*/` (introduced in GitLab 11.11)
|
||||||
|
|
||||||
It is possible perform pattern matching against a variable and regular
|
Variable pattern matching with regular expressions uses the
|
||||||
expression. Expression like this evaluates to truth if matches are found
|
[RE2 regular expression syntax](https://github.com/google/re2/wiki/Syntax).
|
||||||
when using `=~`. It evaluates to truth if matches are not found when `!~` is used.
|
Expressions evaluate as `true` if:
|
||||||
|
|
||||||
|
- Matches are found when using `=~`.
|
||||||
|
- Matches are *not* found when using `!~`.
|
||||||
|
|
||||||
Pattern matching is case-sensitive by default. Use `i` flag modifier, like
|
Pattern matching is case-sensitive by default. Use `i` flag modifier, like
|
||||||
`/pattern/i` to make a pattern case-insensitive.
|
`/pattern/i` to make a pattern case-insensitive.
|
||||||
|
|
|
@ -857,7 +857,10 @@ In this example, if the first rule:
|
||||||
|
|
||||||
`rules:if` differs slightly from `only:variables` by accepting only a single
|
`rules:if` differs slightly from `only:variables` by accepting only a single
|
||||||
expression string, rather than an array of them. Any set of expressions to be
|
expression string, rather than an array of them. Any set of expressions to be
|
||||||
evaluated should be conjoined into a single expression using `&&` or `||`. For example:
|
evaluated should be conjoined into a single expression using `&&` or `||`, and use
|
||||||
|
the [variable matching syntax](../variables/README.md#supported-syntax).
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
job:
|
job:
|
||||||
|
|
|
@ -9,11 +9,11 @@ at midnight UTC and that they can be only managed by [maintainers](../../permiss
|
||||||
|
|
||||||
## Creating a Deploy Token
|
## Creating a Deploy Token
|
||||||
|
|
||||||
You can create as many deploy tokens as you like from the settings of your project:
|
You can create as many deploy tokens as you like from the settings of your project. Alternatively, you can also create [group-scoped deploy tokens](#group-deploy-token).
|
||||||
|
|
||||||
1. Log in to your GitLab account.
|
1. Log in to your GitLab account.
|
||||||
1. Go to the project you want to create Deploy Tokens for.
|
1. Go to the project (or group) you want to create Deploy Tokens for.
|
||||||
1. Go to **Settings** > **Repository**.
|
1. Go to **{settings}** **Settings** > **CI / CD**.
|
||||||
1. Click on "Expand" on **Deploy Tokens** section.
|
1. Click on "Expand" on **Deploy Tokens** section.
|
||||||
1. Choose a name, expiry date (optional), and username (optional) for the token.
|
1. Choose a name, expiry date (optional), and username (optional) for the token.
|
||||||
1. Choose the [desired scopes](#limiting-scopes-of-a-deploy-token).
|
1. Choose the [desired scopes](#limiting-scopes-of-a-deploy-token).
|
||||||
|
@ -77,6 +77,22 @@ docker login -u <username> -p <deploy_token> registry.example.com
|
||||||
Just replace `<username>` and `<deploy_token>` with the proper values. Then you can simply
|
Just replace `<username>` and `<deploy_token>` with the proper values. Then you can simply
|
||||||
pull images from your Container Registry.
|
pull images from your Container Registry.
|
||||||
|
|
||||||
|
### Group Deploy Token
|
||||||
|
|
||||||
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/21765) in GitLab 12.9.
|
||||||
|
|
||||||
|
A deploy token created at the group level can be used across all projects that
|
||||||
|
belong either to the specific group or to one of its subgroups.
|
||||||
|
|
||||||
|
To use a group deploy token:
|
||||||
|
|
||||||
|
1. [Create](#creating-a-deploy-token) a deploy token for a group.
|
||||||
|
1. Use it the same way you use a project deploy token when
|
||||||
|
[cloning a repository](#git-clone-a-repository).
|
||||||
|
|
||||||
|
The scopes applied to a group deploy token (such as `read_repository`) will
|
||||||
|
apply consistently when cloning the repository of related projects.
|
||||||
|
|
||||||
### GitLab Deploy Token
|
### GitLab Deploy Token
|
||||||
|
|
||||||
> [Introduced][ce-18414] in GitLab 10.8.
|
> [Introduced][ce-18414] in GitLab 10.8.
|
||||||
|
|
|
@ -41,7 +41,7 @@ groups:
|
||||||
- [Label](../project/labels.md)
|
- [Label](../project/labels.md)
|
||||||
- My-reaction
|
- My-reaction
|
||||||
- Confidential
|
- Confidential
|
||||||
- Epic ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/195704) in GitLab 12.8)
|
- Epic ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/195704) in GitLab 12.9)
|
||||||
- Search for this text
|
- Search for this text
|
||||||
1. Select or type the operator to use for filtering the attribute. The following operators are
|
1. Select or type the operator to use for filtering the attribute. The following operators are
|
||||||
available:
|
available:
|
||||||
|
|
|
@ -215,7 +215,7 @@ module Gitlab
|
||||||
fk_name = name || concurrent_foreign_key_name(source, column)
|
fk_name = name || concurrent_foreign_key_name(source, column)
|
||||||
|
|
||||||
unless foreign_key_exists?(source, name: fk_name)
|
unless foreign_key_exists?(source, name: fk_name)
|
||||||
raise "cannot find #{fk_name} on #{source} table"
|
raise missing_schema_object_message(source, "foreign key", fk_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
disable_statement_timeout do
|
disable_statement_timeout do
|
||||||
|
@ -931,7 +931,10 @@ module Gitlab
|
||||||
def column_for(table, name)
|
def column_for(table, name)
|
||||||
name = name.to_s
|
name = name.to_s
|
||||||
|
|
||||||
columns(table).find { |column| column.name == name }
|
column = columns(table).find { |column| column.name == name }
|
||||||
|
raise(missing_schema_object_message(table, "column", name)) if column.nil?
|
||||||
|
|
||||||
|
column
|
||||||
end
|
end
|
||||||
|
|
||||||
# This will replace the first occurrence of a string in a column with
|
# This will replace the first occurrence of a string in a column with
|
||||||
|
@ -1166,6 +1169,18 @@ into similar problems in the future (e.g. when new tables are created).
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def missing_schema_object_message(table, type, name)
|
||||||
|
<<~MESSAGE
|
||||||
|
Could not find #{type} "#{name}" on table "#{table}" which was referenced during the migration.
|
||||||
|
This issue could be caused by the database schema straying from the expected state.
|
||||||
|
|
||||||
|
To resolve this issue, please verify:
|
||||||
|
1. all previous migrations have completed
|
||||||
|
2. the database objects used in this migration match the Rails definition in schema.rb or structure.sql
|
||||||
|
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
|
||||||
def tables_match?(target_table, foreign_key_table)
|
def tables_match?(target_table, foreign_key_table)
|
||||||
target_table.blank? || foreign_key_table == target_table
|
target_table.blank? || foreign_key_table == target_table
|
||||||
end
|
end
|
||||||
|
|
|
@ -383,7 +383,8 @@ describe Gitlab::Database::MigrationHelpers do
|
||||||
it 'raises an error' do
|
it 'raises an error' do
|
||||||
expect(model).to receive(:foreign_key_exists?).and_return(false)
|
expect(model).to receive(:foreign_key_exists?).and_return(false)
|
||||||
|
|
||||||
expect { model.validate_foreign_key(:projects, :user_id) }.to raise_error(/cannot find/)
|
error_message = /Could not find foreign key "fk_name" on table "projects"/
|
||||||
|
expect { model.validate_foreign_key(:projects, :user_id, name: :fk_name) }.to raise_error(error_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -587,6 +588,8 @@ describe Gitlab::Database::MigrationHelpers do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#add_column_with_default' do
|
describe '#add_column_with_default' do
|
||||||
|
let(:column) { Project.columns.find { |c| c.name == "id" } }
|
||||||
|
|
||||||
context 'outside of a transaction' do
|
context 'outside of a transaction' do
|
||||||
context 'when a column limit is not set' do
|
context 'when a column limit is not set' do
|
||||||
before do
|
before do
|
||||||
|
@ -601,6 +604,9 @@ describe Gitlab::Database::MigrationHelpers do
|
||||||
|
|
||||||
expect(model).to receive(:change_column_default)
|
expect(model).to receive(:change_column_default)
|
||||||
.with(:projects, :foo, 10)
|
.with(:projects, :foo, 10)
|
||||||
|
|
||||||
|
expect(model).to receive(:column_for)
|
||||||
|
.with(:projects, :foo).and_return(column)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds the column while allowing NULL values' do
|
it 'adds the column while allowing NULL values' do
|
||||||
|
@ -655,6 +661,7 @@ describe Gitlab::Database::MigrationHelpers do
|
||||||
it 'adds the column with a limit' do
|
it 'adds the column with a limit' do
|
||||||
allow(model).to receive(:transaction_open?).and_return(false)
|
allow(model).to receive(:transaction_open?).and_return(false)
|
||||||
allow(model).to receive(:transaction).and_yield
|
allow(model).to receive(:transaction).and_yield
|
||||||
|
allow(model).to receive(:column_for).with(:projects, :foo).and_return(column)
|
||||||
allow(model).to receive(:update_column_in_batches).with(:projects, :foo, 10)
|
allow(model).to receive(:update_column_in_batches).with(:projects, :foo, 10)
|
||||||
allow(model).to receive(:change_column_null).with(:projects, :foo, false)
|
allow(model).to receive(:change_column_null).with(:projects, :foo, false)
|
||||||
allow(model).to receive(:change_column_default).with(:projects, :foo, 10)
|
allow(model).to receive(:change_column_default).with(:projects, :foo, 10)
|
||||||
|
@ -721,6 +728,10 @@ describe Gitlab::Database::MigrationHelpers do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(model).to receive(:transaction_open?).and_return(false)
|
allow(model).to receive(:transaction_open?).and_return(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the column to rename exists' do
|
||||||
|
before do
|
||||||
allow(model).to receive(:column_for).and_return(old_column)
|
allow(model).to receive(:column_for).and_return(old_column)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -768,6 +779,20 @@ describe Gitlab::Database::MigrationHelpers do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the column to be renamed does not exist' do
|
||||||
|
before do
|
||||||
|
allow(model).to receive(:columns).and_return([])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises an error with appropriate message' do
|
||||||
|
expect(model).to receive(:check_trigger_permissions!).with(:users)
|
||||||
|
|
||||||
|
error_message = /Could not find column "missing_column" on table "users"/
|
||||||
|
expect { model.rename_column_concurrently(:users, :missing_column, :new) }.to raise_error(error_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#undo_rename_column_concurrently' do
|
describe '#undo_rename_column_concurrently' do
|
||||||
|
@ -1133,8 +1158,9 @@ describe Gitlab::Database::MigrationHelpers do
|
||||||
expect(column.name).to eq('id')
|
expect(column.name).to eq('id')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns nil when a column does not exist' do
|
it 'raises an error when a column does not exist' do
|
||||||
expect(model.column_for(:users, :kittens)).to be_nil
|
error_message = /Could not find column "kittens" on table "users"/
|
||||||
|
expect { model.column_for(:users, :kittens) }.to raise_error(error_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,10 @@ RSpec.describe ResourceLabelEvent, type: :model do
|
||||||
|
|
||||||
it_behaves_like 'having unique enum values'
|
it_behaves_like 'having unique enum values'
|
||||||
|
|
||||||
|
it_behaves_like 'a resource event'
|
||||||
|
it_behaves_like 'a resource event for issues'
|
||||||
|
it_behaves_like 'a resource event for merge requests'
|
||||||
|
|
||||||
describe 'associations' do
|
describe 'associations' do
|
||||||
it { is_expected.to belong_to(:user) }
|
it { is_expected.to belong_to(:user) }
|
||||||
it { is_expected.to belong_to(:issue) }
|
it { is_expected.to belong_to(:issue) }
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe ResourceWeightEvent, type: :model do
|
RSpec.describe ResourceWeightEvent, type: :model do
|
||||||
|
it_behaves_like 'a resource event'
|
||||||
|
it_behaves_like 'a resource event for issues'
|
||||||
|
|
||||||
let_it_be(:user1) { create(:user) }
|
let_it_be(:user1) { create(:user) }
|
||||||
let_it_be(:user2) { create(:user) }
|
let_it_be(:user2) { create(:user) }
|
||||||
|
|
||||||
|
@ -11,13 +14,11 @@ RSpec.describe ResourceWeightEvent, type: :model do
|
||||||
let_it_be(:issue3) { create(:issue, author: user2) }
|
let_it_be(:issue3) { create(:issue, author: user2) }
|
||||||
|
|
||||||
describe 'validations' do
|
describe 'validations' do
|
||||||
it { is_expected.not_to allow_value(nil).for(:user) }
|
|
||||||
it { is_expected.not_to allow_value(nil).for(:issue) }
|
it { is_expected.not_to allow_value(nil).for(:issue) }
|
||||||
it { is_expected.to allow_value(nil).for(:weight) }
|
it { is_expected.to allow_value(nil).for(:weight) }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'associations' do
|
describe 'associations' do
|
||||||
it { is_expected.to belong_to(:user) }
|
|
||||||
it { is_expected.to belong_to(:issue) }
|
it { is_expected.to belong_to(:issue) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,21 @@ shared_examples 'a resource event' do
|
||||||
let_it_be(:issue2) { create(:issue, author: user1) }
|
let_it_be(:issue2) { create(:issue, author: user1) }
|
||||||
let_it_be(:issue3) { create(:issue, author: user2) }
|
let_it_be(:issue3) { create(:issue, author: user2) }
|
||||||
|
|
||||||
|
describe 'importable' do
|
||||||
|
it { is_expected.to respond_to(:importing?) }
|
||||||
|
it { is_expected.to respond_to(:imported?) }
|
||||||
|
end
|
||||||
|
|
||||||
describe 'validations' do
|
describe 'validations' do
|
||||||
it { is_expected.not_to allow_value(nil).for(:user) }
|
it { is_expected.not_to allow_value(nil).for(:user) }
|
||||||
|
|
||||||
|
context 'when importing' do
|
||||||
|
before do
|
||||||
|
allow(subject).to receive(:importing?).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to allow_value(nil).for(:user) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'associations' do
|
describe 'associations' do
|
||||||
|
|
Loading…
Reference in a new issue