Database space vs. rails/script processing - ruby-on-rails

This may be a dumb/basic question, but I have a model Program with a business type of either "Work", "School", "Church", etc. Right now, it stores these in the database as chars "w","s","c", etc. However, if I do that, I have to run a switch (case in rails) to get the real name. I do these with a few other attributes.
Is it better to just store the exact value in the database instead of running this case statement? I guess its a question of saving database space over the time it takes to process the name (and I guess there is also an issue of code readability).
EDIT
I should clarify, these things only have 4 immutable values. There is an outside chance I may have to add one or two later, but it does not seem to make sense to create a new resource as there is really no CRUD actions done on these attributes.
EDIT
Program.rb
attr_accessible :org_type
validates :org_type, :presence => true.
:inclusion => %w[any c s c] # And have a case later
#OR :inclusion -> $w[Any Corporation School Church]

If you are likely to add more later just make it a resource. It gives you more advantages then disadvantages.
If you did this for performance reasons: First make it working with the resource. Then fix the performance. In this case it looks like premature optimisation. There is no need to not use a Resource here.
Also you expect already that values are being added so that makes the case quite clear.
Though, if you give more info, there might be even better solutions. It depends on which fields you need for each type.

Related

Is there a validation I can use for a specific attribute on all associated records?

I have a Question that has_many :answers (just like SO). I also want each question to have only 1 accepted_answer, so I just added an :accepted attribute to the Answer model that is simply a boolean.
So now, to get the accepted answer for my question, I have written a method on my model that just does this:
def accepted_answer
answers.where(accepted: true)
end
That allows me to do question.accepted_answer and it returns an ActiveRelation object like you would expect.
Nothing fancy. Simple and effective.
However, what I want to ensure though is that there can only be one answer on each question that is accepted: true at any moment in time.
What's the best way to approach this?
I thought about using a validator, but I couldn't find one that handled associated objects in this way. There are some that have bits & pieces that are interesting, but I can't quite fit all the pieces together. For instance, presence is interesting as is absence and validates_with (but this last one feels too heavy).
Suggestions?
Most likely the best way would be to use after_add callback (an example here), which would set to false all your existing accepted records via update_all and the latest answer with accepted set to true. It all depends on your logic.
You can also employ some other callbacks such as before_save, before_update and such with the similar functionality depending on your application specifics.
It is not quit a validation, but it will effectively maintain the required state of your model. Besides, the purpose of the validations to warn you when something is not valid, but I guess you want to save your object without such failures, and just enforce a single accepted answer.
Let me know in case you want to stop adding answers after the first one was accepted. In this case it would require a different functionality.

What is the Rails Convention for validating field length?

With ActiveRecord models, I know you can validate the length of an input field like so
class User
validates :user_name, length: { maximum: 20 }
end
However, one of the design patterns in Rails recommends thin models. If you have a ton of validations, the above code might seem intimidating. I read there was another way you could do this.
You can simply use an ActiveRecord::Schema to accomplish the same task.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :user_name, limit: 20
end
end
end
That accomplishes the exact same thing only you don't even need the second line in your Users model.
What is the standard Rails convention regarding this?
Some people would argue that you have to have skinny controllers and skinny models. However, this can create several additional classes in your application.
Sometimes having a fat model if documented and laid out logically can be easier to read. I will ignore the 'best practices' if it makes the code easier to read as I may not always be the only person touching that code. If the application scales to a point where multiple people will be accessing the same files, I will consider extracting it at that point as a refactor. However, this has rarely been the case.
While it is good to set limits on your database, you also want to have client validations to prevent someone having their data truncated with no feedback to them. For example, (a really horrible example), if you were to limit the username of an User to only six characters and I type in kobaltz as my username, I will wonder why my username/password never works as the database truncated it to kobalt. You will also run into issues where MySQL (or similar) will throw database level errors which is annoying to fix/troubleshoot. You also have to consider if modifying a database in production, if you set the limits where they did not exist before, you could end up corrupting your data.
Having a few validations in your model does not make it a 'fat' model in my opinion. It makes it easier to read. If you're not using an IDE like RubyMine and only using an editor, you do not have the luxury of Jump to Definition which can make the abstraction of your model easier to follow.
If you use second approach, you won't be able to get the error. Its on mysql level and not on model level, so active record won't tell you the reason for user not getting created or updated.
object.errors
will be empty.
Check this
http://apidock.com/rails/ActiveModel/Errors/full_messages

Best practices regarding per-user settings and predefining options

I want to save settings for my users and some of them would be one out of a predefined list! Using https://github.com/ledermann/rails-settings ATM.
The setting for f.e. weight_unit would be out of [:kg, :lb].
I don't really want to hardcode that stuff into controller or view code.
It's kind of a common functionality, so I was wondering: Did anyone come up with some way of abstracting that business into class constants or the database in a DRY fashion?
Usually, when I have to store some not important information which I don't care to query individually, I store them on a serialized column.
In your case you could create a new column in your users table (for example call it "settings").
After that you add to user model
serialize :settings, Hash
from this moment you can put whatever you like into settings, for example
user.settings = {:weight_unit => :kg, :other_setting1 => 'foo', :other_setting2 => 'bar'}
and saving with user.save you will get, in settings column, the serialized data.
Rails does also de-serialize it so after fetching a user's record, calling user.settings, you will get all saved settings for the user.
To get more information on serialize() refer to docs: http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
UPDATE1
To ensure that settings are in the predefined list you can use validations on your user model.
UPDATE2
Usually, if there are some pre-defined values it's a good habit to store them in a constant inside the related model, in this way you have access to them from model (inside and outside). Acceptable values does not change by instance so it makes sense to share them between all. An example which is more valuable than any word. Defining in your User model:
ALLOWED_SETTINGS = {:weight_unit => [:kg, :lb],
:eyes_color => [:green, :blue, :brows, :black],
:hair_length => [:short, :long]}
you can use it BOTH
outside the model itself, doing
User::ALLOWED_SETTINGS
inside your model (in validations, instance methods or wherever you want) using:
ALLOWED_SETTINGS
Based on your question, it sounds like these are more configuration options that a particular user will choose from that may be quite static, rather than dynamic in nature in that the options can change over time. For example, I doubt you'll be adding various other weight_units other than :kg and :lb, but it's possible I'm misreading your question.
If I am reading this correctly, I would recommend (and have used) a yml file in the config/ directory for values such as this. The yml file is accessible app wide and all your "settings" could live in one file. These could then be loaded into your models as constants, and serialized as #SDp suggests. However, I tend to err on the side of caution, especially when thinking that perhaps these "common values" may want to be queried some day, so I would prefer to have each of these as a column on a table rather than a single serialized value. The overhead isn't that much more, and you would gain a lot of additional built-in benefits from Rails having them be individual columns.
That said, I have personally used hstore with Postgres with great success, doing just what you are describing. However, the reason I chose to use an hstore over individual columns was because I was storing multiple different demographics, in which all of the demographics could change over time (e.g. some keys could be added, and more importantly, some keys could be removed.) It sounds like in your case it's highly unlikely you'll be removing keys as these are basic traits, but again, I could be wrong.
TL;DR - I feel that unless you have a compelling reason (such as regularly adding and/or removing keys/settings), these should be individual columns on a database table. If you strongly feel these should be stored in the database serialized, and you're using Postgres, check out hstore.
If you are using PostgreSQL, I think you can watch to HStore with Rails 4 + this gem https://github.com/devmynd/hstore_accessor

Validation on model with 'intentional' invalid data

The data source I am working with is terrible. Some places where you would expect integers, you get "Three". In the phone number field, you may get "the phone # is xxx". Some fields are simply blank.
This is OK, as I'm parsing each field so "Three" will end up in my model as integer 3, phone numbers (and such) will be extracted via regex. Users of the service KNOW that the data is sketchy and incomplete, as it's an unfortunate fact of the way our data source is maintained and there's nothing we can do about it but step up our parsing game! As an aside, we are producing our own version of the data slowly as we parse more and more of the original data, but this poor source has to do for now.
So users select the data they wish to parse, and we do what we can, returning a partial/incorrect model. Now the final model that we want to store should be validated - there are certain fields that can't be null, certain strings must adhere to a format and so on.
The flow of the app is:
User tells the service which data to
parse.
Service goes off and grabs
the data, parses what it can and
returns a partial model with
whatever data it could retrieve.
We display the data to the user,
allowing them to make corrections
and to fill in any mandatory fields
for which no data was collected.
This user-corrected data is to be
saved, and therefore validated.
If validation fails, show data again
for user to make fixes, rinse &
repeat.
What is the best way to go about having a model which starts off being potentially completely invalid or containing no data, but which needs to be validated eventually? The two ways I've thought of (and partially implemented) are:
2 models - a Data model, which has validations etc, and an UnconfirmedData model, which has no validations. The original data is put into an UnconfirmedData model until the user has made their corrections, at which point it it put into a Data model and validation is attempted.
One model, with a "confirmed data" flag, with validation being performed manually rather than Rails' validation.
In practice I lean towards using 2 models, but I'm pretty new to Rails so I thought there me be a nicer way to do this, Rails has a habit of surprising me like that :)
Must you save your data in between requests? If so, I would use your two model format, but use Single Table Inheritance (STI) to keep things dry.
The first model, the one responsible for the parsing and the rendering and the doing-the-best-it-can, shouldn't have any validations or restrictions on saving it. It should however have the type column in the migration so you can use the inheritance goodness. If you don't know what I'm talking about, read up on the wealth of information on STI, a good place to start would be a definitive guide.
The second model would be the one you would use in the rest of the application, the strict model, the one which has all the validations. Every time a user submitted reworked and potentially valid data, your app would try and move your instance of the open model created from the params, to an instance of the second model, and see if it was valid. If it was, save it to the database, and the type attribute will change, and everything will be wonderful. If it isn't valid, save the first instance, and return the second instance to the user so the validation error messages can be used.
class ArticleData < ActiveRecord::Base
def parse_from_url(url)
# parses some stuff from the data source
end
end
class Article < ArticleData
validates_presence_of :title, :body
validates_length_of :title, :greater_than => 20
# ...
end
You'll need a pretty intense controller action to facilitate the above process, but it shouldn't be too difficult. In the rest of your application, make sure you run your queries on the Article model to only get back valid ones.
Hope this helps!
Using one model should be straightforward enough. You'll need an attribute/method to determine whether the validations should be performed. You can pass :if => to bypass/enable them:
validates_presence_of :title, :if => :should_validate
should_validate can be a simple boolean attribute that returns false when the model instance is "provisional", or a more complicated method if necessary.

what is the right way to model status values as an association in Rails?

I have a model called Contacts.
Contacts can have different status "bad, positive, wrong..."
These status may need to be changed over time, but across all contacts, they are the same options.
Should I model it this way:
Contacts.rb
belongs_to :status_contact
StatusContacts.rb
has_many :contacts
Then I manually populate the types of status in the table?
I then want to use Ajax to click a button corresponding to a value to update the value for Contacts.
It looks like you're trying to ensure that the values for your status are always going to restricted to a set of possible answers of your choosing. If that's all you're trying to do, there's no special need for a separate table. You can use the magic of ActiveRecord validations instead here.
First, create a string database column for Contact called :status.
Then you can use a validation to ensure that the values are limited to the ones you want. In Rails 3, you can do it like this:
validate :status, :inclusion => { :in => %w( bad positive wrong ) }
(If you're using Rails 2, use #validates_inclusion_of instead.)
In ActiveRecord, validations check that the object's values are valid before saving; it refuses to persist the object into the database until all validations pass.
Your naming strikes me as a little weird—ContactStatus sounds a little nicer to me—but I see this as being the general idea to achieve what you want.
No clear answer yet --- I think I need to use the table because it would allow the users to add and modify the types of status used across their application.

Resources