I'm looking documentation/tips on importing data from an external API.
I'm building a website where users can add a company to their profile. However, I want people to be unable to create duplicate companies.
Therefore I want to call upon data from the official government API to verify the existence of the dossier integer by matching it to the integer entered on the form.
Any suggestions/explanations/tips are welcomed. If I find the solution I will obviously share this here.
Thanks in advance,
Julian
You can add a unique constrain to the name of the company, so you avoid duplicates
In Company.rb you can add the following validation:
validates :name, uniqueness: true
You also can use find_or_create_by like this to avoid duplicates
Company.find_or_create_by(first_name: 'company_name') do |company|
company.location = 'Wherever'
end
Here you are saying: Find the first company named 'company_name' or create a new one with a different location.
References:
reference for model validations
reference for find_or_create_by
Related
I am having problems with the uniqueness validator in Rails 6 when I use the scope attribute.
I have a many-to-many relationship between Product and Machine. My join table is called ProductMachine.
In my join table I have the following validation:
validates :product_id, uniqueness: { scope: :machine }
I am building an import tool that allows me to create the associations for products and machines via a csv import. In this import, I have code that creates new records like this:
machine = Machine.first
machine.product_machines.new(product_id: 1234)
machine.product_machines.new(product_id: 1234)
machine.product_machines.new(product_id: 5678)
machine.save!
When I call machine.save! the new product_machines are inserted into the database and the validation does not fail. If I run this same exact code a second time, it fails as expected. I assume this is because the scope is making a where clause in the validation which causes the new records to be missed since the are not persisted. How can this be fixed? Here is the documentation for the scoped validation.
https://guides.rubyonrails.org/active_record_validations.html#uniqueness
You're validating that for any given machine it can only link to the same product once. You're not validating that you can only link one machine to one product.
Normally these sorts of join tables have a UNIQUE constraint as well to be sure you don't have duplicate links.
If you're trying to enforce one link and one link only, making that table effectively a one-to-one, you need to constrain differently.
I am trying to create a Rails app and I have a database consisting of author and a quotation by that author.
Now different users can choose to destroy or kill quotations from the database however it must only be deleted for that particular user i.e other users should still be able to see quotes that they didn't delete even if another user did.
I know that I would need to implement cookies but other than that I am unsure how to proceed. Can anyone point me to a tutorial or give me some pointers to get started on this complex task?
You surely have a User model in your application - one 'Rails-like' way to go about this would be to add a has_and_belongs_to_many relationship between User and Quotation.
This creates a relationship between each individual user and 'their' quotations. This relationship can be deleted without actually deleting a quotation, so all quotations would still be available to other users. If you want each user to be able to see all quotations by default, you would need to set up the relationship in advance.
Assuming you are using Devise to log your users in, all you'd need to do then is to replace Quotation.all with current_user.quotations in whichever controller you are using to display quotations.
The Rails guide linked above is quite helpful but basically you just need to add something like the following:
class User
has_and_belongs_to_many :quotations
before_create :add_quotations
def add_quotations
self.quotations << Quotation.all
end
#etc...
end
class Quotation
has_and_belongs_to_many :users
#etc...
end
and then run a migration adding a new table called users_quotations with the columns user_id and quotation_id.
EDIT
As #Yule pointed out this wouldn't let users see any quotations that were created after they were, and it would be quite annoying to have to set up the join tables in advance, so a more efficient way would be to have an excluded_quotations join table instead. So users can see all quotations except the ones that they have excluded.
I've created 2 tables, one for users and one for admins.
I created 2 tables as they both collect different information, but I want to be able to allow a sign in using an email address and password from both the admin and user tables via the same form.
Is this possible? I've looked around and people seem to have created 1 users table and added an admin boolean, but I wanted to avoid this and I didn't want to collect unnecessary data if I didn't need to.
Any help and assistance about how to best go around this would be great.
If you are implementing something from scratch, then it is simply a matter of coding it. I think this approach has some inherent flaws and I would avoid it.
If you want to have some segregation on the model side of things, I suggest you use STI. That way there is some shared behaviour/attributes and the distinctions can be coded separately, so you have your protection.
If you have plenty of distinct attributes, I would suggest separating them from your user/admin and creating an "admin_profile" model that belongs_to :admin and a "user_profile" that belongs_to :user.
And to make coding "transparent", you can create accessors in your admin model class to get/set the profile attributes seamlessly. Say you have an is_cool attribute on the admin_profile model, but you'd like to access it as
imadmin.is_cool
You can have in your admin.rb model
has_one :admin_profile
def is_cool
self.admin_profile.is_cool
end
be careful cause the has_one relationship may return nil if there is no profile associated with the admin/user.
I am looking on trying to use acts_as_paranoid plugin for soft delete of records. I was earlier managing it using a flag in the db. I know that this plugin will omit a record from searches and finds if the record is soft deleted. What I want to know is if I have a validation in the model like validates_uniqueness_of :email and I deleted(soft deleted) the record having email 'prince#gmail.com'. Now when I try to create a new user having same email, will the validation work and prevents the creation of the new record. Or will it omit the soft deleted record as it does for finds? (I would like this to happen, of course.)
acts_as_paranoid does not reimplement validates_uniqueness_of, so if you have (soft) deleted a record with email 'prince#gmail.com' you cannot create a new record with the same email.
The easy fix for this is to add a scope to validates_uniqueness_of:
validates_uniqueness_of :email, :scope => :deleted_at
This way you can have any number of (soft) deleted records with email 'prince#gmail.com' and still create a new record with the same email.
From our testing, the patching that acts_as_paranoid does affect the deletes, so you would end up with two records. From most of the conversations around the web, this is probably what you expect.
In our case, we didn't want this. When we create another user with the same email, we want to "undelete" the first user, and we'd like the validations to hep us with this. Turns out that we couldn't figure out a way to do what we wanted. We ended up not using acts_as_paranoid in this case, but we are still considering going back.
We did find one patch that allowed passing in a flag to validations (:with_deleted => true), so that you could explicitly control this. This seems like a good idea, but we decided not to pursue it. Unfortunately this issue highlights that this approach is a bit of a "leaky abstraction" and has to be used with care.
if yor are using "rails3_acts_as_paranoid" then have provision for above mentioned issue,
ActiveRecord's built-in uniqueness validation does not account for records deleted by ActsAsParanoid. If you want to check for uniqueness among non-deleted records only, use the macro validates_as_paranoid in your model. Then, instead of using validates_uniqueness_of, use validates_uniqueness_of_without_deleted. This will keep deleted records from counting against the uniqueness check.
Need to specify following way ,
acts_as_paranoid
validates_as_paranoid
validates_uniqueness_of_without_deleted :name
I would like to allow users to write comments on a site. If they are registered users their username is displayed with the comment, otherwise allow them to type in a name which is displayed instead.
I was going to create a default anonymous user in the database and link every non-registered comment to that user. Would there be a better way to do it?
Any advice appreciated.
Thanks.
The problem with creating an anonymous user is then you need to check if a comment was made by a "real" user, or an anonymous one when displaying the name, so that introduces complexity. Plus, if you have a way of viewing their profile page, which may include posting history, you'd need to exclude the anonymous user with an exception.
Generally it's better to have a column on your comments which represents the user's visible name, and just show that if provided, or the registered user's name otherwise. For instance, your view helper might look like this:
class Comment < ActiveRecord::Base
belongs_to :user
def user_name
self.anonymous_name or (self.user and self.user.name) or 'Anonymous'
end
end
This will display the contents of the anonymous_name field of the Comment record, or the user's name if a user is assigned, or 'Anonymous' as a last-ditch effort to show something.
Sometimes it's advantageous to actually de-normalize a lot of the database when dealing with large numbers of comments so you don't have to load in the user table via a join simply to display a name. Populating this field with the user's name, even if they're not anonymous, may help with this, though it does mean these values need to be updated when a username changes, presuming that's even possible.
I think you can make user_id on your comment model nullable since you want to allow non registered users to add comments as well. As far as adding names for the non registered users are concerned, there are two options for that
option 1. Add a column on Comment model and name it like anonymous_user where you will store names of non registered users
option 2. Create a another model AnonymousCommentor with name and comment_id attributes.
If you are going to use anonymous users for other things as well apart from comment in your application then you can make it polymorphic and use a suitable name like AnonymousUser instead of AnonymousCommentor