I have to prepare a rather large amount of seed data for a Rails application. Based on my limited experience, I know of two ways to do it but want to know which offers the most flexibility.
One, I could do it with Rails and just prepare the seed data the way it's used in the seeds.rb file
User.create!( name: "John" )
Or, I could create a json document of the data. For example, I know that Mongodb lets you import json documents directly into the database. I'm not sure about other databases...
It occurred to me that a json document might be the most flexible, because I suppose you could also use a regular expression script to turn the json into something like this User.create!( name: "John" )
However, I'm wondering if there's any other issues I should consider...
I'm a StackOverflow newbie, so can't reply to the comments above.
I've been trying to do something similar, the mass assignment protection issue came up for me. An idea that I came across in my research was to use:
without_protection: true
I found this worked using rails 3.2.3 For example:
json = ActiveSupport::JSON.decode(File.read('db/seeds/data.json'))
json.each do |a|
Country.create!(a['data'], without_protection: true)
end
See http://snippets.aktagon.com/snippets/401-How-to-seed-your-database-with-JSON-YAML-data-in-Rails
One issue to consider is that you can't always pass all the parameters through the constructor. Consider this:
class User
include Mongoid::Document
field :name
field :role
validates :name, presence: true
validates :role, presence: true
attr_accessible :name
end
If you have something like User.create({name: 'John', role: 'admin'}), then your seed will fail because role will not be able to be assigned.
Related
I hope the title is not too unclear.
I am making arails app and I have a question about rails validation. Consider this code in the User,rb model file:
validates :name,
presence: true,
length: { maximum: 50 },
uniqueness: { case_sensitive: false }
I am using the friendly_id gem to generate slugs for the users. I wont allow users to change their name. What I now need is to ensure that Names are unique in such a way that there will be no UUID's appended to slugs if two people have the same name converted in ascii approximation.
Current behaviour is:
User 1 signs up with a name and gets a slug like this:
name: "Jaiel" slug: "jaiel"
User 2 now does the same name but a bit different:
name: "Jàìèl" slug: "jaiel-6558c3f1-e6a1-4199-a53e-4ccc565657d4"
The problem here as you see I want such a uniqueness validation that User 2 would have been rejected because both names would generate the slug "jaiel" for their friendly_id's
I would appreciate your help on that matter
Thanks
Take a look into ActiveSupport::Inflector.transliterate:
ActiveSupport::Inflector.transliterate('Ærøskøbing')
#=> "AEroskobing"
Also, with this type of validation you might want to go with custom validation (alongside the one you already have):
class User
validate :unique_slug
private
def unique_slug
names = self.class.all.map(&:asci_name)
raise ActiveRecord::RecordInvalid.new(self) if names.include?(asci_name)
end
def asci_name
ActiveSupport::Inflector.transliterate(name)
end
end
Obviously, this is super inefficient to query whole table on each validation, but this is just to point you into one of the possible directions.
Another option would be going for a callback. Transliterating the name upon creation:
before_validation: :transliterate_name
def transliterate_name
self.name = ActiveSupport::Inflector.transliterate(name)
end
It will first transliterate the name, then validate uniqueness of already transliterated name with the validation you have. Looks like a solution, definitely not as heavy as initial one.
I have a form field in ROR 4 app called as 'measure'. It is not a database column, but its values will help model create child entries of its own via acts_as_tree : https://github.com/rails/acts_as_tree
I have to throw a validation when 'measure' is invalid. So I have created a virtual attribute known as measure and check for its validations only on a certain condition.
model someModel
attr_accessor :measure
validates_presence_of :measure, :if => condition?
Problem is when I am saving the code, I am thrown a validation which is fine. I am also thrown the same validation when I am trying to update the record in some other method of the model. The only way to surpass that is by writing this code:
# I do not want to do this, is there a better way?
self.measure = "someRandomvalue"
self.save
I am making this as virtual attribute only for throwing validations. Is there a better way of throwing validations? The form has other validations, I do not want the error for this validations to be shown differently just because it is not an attribute.
I want it to validated only when active record is saved via create and update action of the controller and not when it is being updated by some random method of model.
I have seen other developers in my team doing similar thing and was always curious about one thing - "What are you trying to achieve doing things the way you are doing?". You see, I am not sure if validators should be used for values that will not be serialized.
Anyways, you may try using format validator instead of presence, which worked in my team's case:
# Rails 3/4
validates :measure, format: { with: /^.+$/, allow_nil: true }
# Rails 2
validates_format_of :measure, :with => /^.+$/, :allow_nil => true
You may also try using allow_blank instead of allow_nil.
I would rather create a custom validator along the lines of validates_accessor_of for values that I know will never be serialized.
HTH
I have a simple ActiveRecord class that logs an event and stores some additional data using the serialize method. It has one string column for an event and a text column to store a data object.
# DB Columns
# event => string
# data => text
#
class MyLog < ActiveRecord::Base
serialize :data
validates :event, :data, :presence => true
end
In my controller I would like to take user submitted information and include it as the data:
class ContactFormController < ApplicationController
def send_message
...
data = {name: params[:name], email: params[:email], message: params[:message]}
MyLog.create(event: "User submitted contact form", data: data)
...
end
end
Questions
The serialize method uses YAML by default to store objects like this. Is there a security risk here in the case that a user submits some crafty code that is passed through the parameters? Is there a chance for user submitted Ruby code to be executed when the data field is retrieved and deserialized?
My goal is to provide a way to log events from anywhere in my app and store data of any sort about that event. Is there a better way to preform this than what I have set up here?
In general terms, it's perfectly fine to serialize anything you want. User data of any kind is acceptable.
This presumes you're patched up to the absolutely latest version of Rails 3.2 or 4.0. There have been some issues with YAML and JSON serialization in the past but these have been patched and resolved.
Test your application against known vulnerabilities using a tool like GemCanary to be sure you're current, and to catch future problems.
I have added a validation like this one to my model:
validates :name, uniqueness: {scope: user_id}
And added an add_index like this on my migration:
add_index(:posts, :name)
But I just read on the rails api page the part about data integrity.
And I was wondering if I will have any integrity errors on my models, so my question is: should I rewrite my indexes as?
add_index(:posts, [:name, :user_id]), unique: true
Thanks all,
The data integrity you're talking about can be enforced at 2 levels as you probably already know: at the application level and at the database level.
At the application level: the validation you added.
At the database level: the index you suggested
You already set up the first one. So, as long as everything goes through your Rails model to be saved in db, you won't have any db integrity issue.
However, if other third-party applications may write to your db, it is not a bad idea to enforce the uniqueness also at the db level.
And even if the first one is sufficient, it is not a bad idea neither to set up the second.
In addition, if you happen to often query the name associated with a user_id, it is actually better to use the add_index(:posts, [:name, :user_id]), making your queries a bit faster.
yes - that would be a good idea. Your model validation implies a composite primary key.
So, I am having some issues with user authentication in embedded documents. I have two documents, one embedded in the other. A business has many members. The models look like this:
class Member
include Mongoid::Document
field :username, type: String
field :password, type: String
embedded_in :business
validates :username, :presence => true, :uniqueness => true, :length => 5..60
end
class Business
include Mongoid::Document
field :name, type: String
embeds_many :members
end
The problem is that it isn't validating the username's uniqueness in each model. When I save a member within a business, I can save a thousand of the same name. This of course is not going to work for a good authentication system. I am using Mongoid 2, Rails 3, and Ruby 1.9
This is a normal behavior when using embedded documents as explained here: MongoID validation
validates_uniqueness_of
Validate that the field is unique in the database: Note that for
embedded documents, this will only check that the field is unique
within the context of the parent document, not the entire database.
I think you want to try to create an Index in the username field that would ensure uniqueness among all the objects of that collection. Something like this:
ensureIndex({username:1},{unique:true});
EDIT: If you want Mongo to throw exception if a document with the same index value exists, you must avoid Mongo to do the “fire and forget” pattern. This means that the database will not wait for a response when you perform an update/write operation on a document.
And you want to pass this parameter: safe:true. By doing so Mongo should raise an exception if for any reason the document can't be inserted.