Having difficulty using validates_uniqueness_of with a specific condition - ruby-on-rails

My model, Goal, has these three attributes: goal_type, goal_length, and is_complete.
Goal belongs_to :user.
goal_type can only be "X", "Y", or "Z"
goal_length can only be "short", "mid", or "long"
is_complete can be true or false
I want there to only ever be one Goal (validates_uniqueness_of) with a specified goal_length and goal_type when looking at Goals that both belong to the same user and have is_complete set to false
Plain english examples:
If a user has a short X goal that they have not yet completed, they cannot create a new short X goal.
If a user has a short X goal that they have completed, they can create a new short X goal.
This validation works, but does not check if the existing goals have their is_complete attribute set to true. If is_complete is true on the previously existing models, it is ok to create a new goal with the same attributes:
validates_uniqueness_of :goal_type, scope: [:goal_length, :user_id]
How would I add a check for the condition where the validation is ignored if the matching previous goal has is_complete set to true ?

This validation appears to work as expected:
validates_uniqueness_of :goal_type, scope: [:goal_length, :user_id], conditions: -> { where(is_complete: false) }

Related

why does activerecord none? return false?

I have a model Account that has_and_belongs_to_many :categories.
When testing whether a given category is already linked to an account (before creating it), I do this:
account = Account.find(1)
account.categories.where(name: "rent").none?
This returns false (although "rent" is a categorie for an account that already exists).
account.categories.where(name: "monkey").none?
returns true
Why doesn't an existing relation return true and an non existing false? Or should I use another method for testing this?
You probably want the any? method since...
[1,2].none?
=> false
[1,2].any?
=> true

validation on uniqueness record on the association relation

I have some query, like a :
Assignment.where(date: "2019-07-01")
.includes(crews: :truck)
.where.not({ crews: {truck_id: nil}})
.count
#=> 2 records.
Here's an example with contain:
Assignment.where(date: "2019-07-01")
.includes(crews: :truck)
.where.not({ crews: {truck_id: nil}})
.distinct.pluck('trucks.name')
#=> ["Mercedes", "BMW"]
I want to check for the uniqueness of truck_id in Assignment.where(date: "2019-07-01")
And in order to attach an existing truck_id to another Assignment object, validation was triggered.
And a message pops up that you cannot add, since such a Truck object is already attached to one of the Assignment on the day that is specified in .where
Please tell me how to implement it correctly. Thank.
If you don't want to write a validate method, you can still use uniqueness options.Use conditional option to tell which rows should do the validation.
validates :truck_id, uniqueness: true, if: Proc.new { |assignment| assignment.on_specified_day? }

How to write a graphQL mutation that allows for partial updates?

So I'm working on trying to learn GraphQL for ruby for a project.
I've almost got some parts of it up and running, but I'm having issues with other parts. There are plenty of tutorials out there that cover ultra-basics, but none of them seem to expand in the right directions.
I have a mutation to update my user. So far so good. I can look up the user by their ID, and update a single specific field. I can extend that to updating two fields.
What I cannot do, and this is looking insane, is generalize those fields -- at all. My user model will wind up with over 20 fields attached to it -- phone numbers, addresses, job title, etc etc.
When I create the mutation, I have to define the arguments that go into the resolve method. So far so good. I then define the fields the mutation can return. Again, so far so good.
Then I get to the actual resolve method.
The initial syntax isn't bad. def resolve(user_id:, name:, email:). Then you discover that despite setting required to false, you have to include all the values. You need to specify default values for the optional variables. So it becomes def resolve(user_id:, name: null, email: null) -- but that actually nulls out those values, you can't do partial updates. Worse yet, imagine having 20 fields you have to set this way. You can play games by trying to convert the arguments into a dictionary and rejecting null values -- but then you can't set properties to nil if they need to be nil again.
The solution: a double splat operator. Your syntax becomes def resolve(user_id:, **args). From what I can tell, it turns all remaining named arguments into a dictionary -- and I think unnamed arguments would become an array. Not sure how it would react with a mix of the two.
Full model becomes:
argument :user_id, ID, required: true#, loads: Types::UserType
argument :name, String, required: false
argument :email, String, required: false
field :user, Types::UserType, null: true
field :errors, Types::UserType, null: true
def resolve(user_id:, **args)
user = User.find(user_id)
if user.update(args)
{
user: user,
errors: []
}
else
{
user: nil,
errors: user.errors.full_messages
}
end
end
end

Uniqueness validation rails 4

I have this uniqueness validation in my model:
validates_uniqueness_of :source_id,
scope: [:year_id],
conditions: -> { where(comment_type_id: CommentType.final.id) },
message: %(
There can be only one final comment per year
)
I have 2 types of comment, the 'CommentType.internal' which can be added to the commentary table many times, and 'CommentType.final' which can be saved once, but via update action it can be modified.
I'm able to save the one record with the final comment_type_id, but when I want to create another regardless of which commentary_type_id I have it still fails on this uniqueness validation.
What am I doing wrong?
This worked for me, I ll answer for anyone else facing the same issue :
validates_uniqueness_of :comment_type_id,
scope: [:year_id, :source_id],
if: ->(cmt) { cmt.comment_type_id == CommentType.final.id) },
message: %(
There can be only one final comment per year
)

Mongoid queries not returning anything on new model fields

I have a Rails application where I am trying to iterate over each object in a Model class depending on whether the object has been archived or not.
class Model
include Mongoid::Document
include Mongoid::Timestamps
field :example_id, type: Integer
field :archived, type: Boolean, default: false
def archive_all
Model.all.where(archived: false).each do |m|
m.archive!
end
end
end
However, the where clause isn't returning anything. When I go into the console and enter these lines, here is what I get:
Model.where(example_id: 3).count #=> 23
Model.where(archived: false).count #=> 0
Model.all.map(&:archived) #=> [false, false, false, ...]
I have other where clauses throughout the application and they seem to work fine. If it makes any difference, the 'archived' field is one that I just recently added.
What is happening here? What am I doing wrong?
When you say:
Model.where(archived: false)
you're looking for documents in MongoDB the archived field is exactly false. If you just added your archived field then none of the documents in your database will have that field (and no, the :default doesn't matter) so there won't be any with archived: false. You're probably better off looking for documents where archived is not true:
Model.where(:archived.ne => true).each(&:archive!)
You might want to add a validation on archived to ensure that it is always true or false and that every document has that field.

Resources