Rails ActiveRecord::Base remap column names programmatically - ruby-on-rails

Given a table with fields like title, title_sp, title_jp, and knowing a particular language value for a user (like jp), what would be a method by which to remap table fields to model attributes at runtime. Something like setting alias_attribute on a per invocation basis in find(*args).
Something along the lines of:
Posts.find(:all, :conditions => {:published => true}, :language => "jp")
and have the returned Posts.title be populated by the value in title_jp. added ideal pointer would also have it able to fall back to title/title_en if title_jp is nil/empty.
I've been digging around overriding .find, but not able to sort out how to bulk remap the field names.

It is dangerous to do such thing. You are able to do this with some find_by_sql, but if you persist the object back, you will propably alter the original title, because the model won't know, that it is not the original value.
The better solution is to create a virtual attribute, which selects the best column to return, based on the parameter. It may be a bit problematic to use, but it is much more safer this way. It is not so hard to write a wrapper, so a whole collection can be accessed with a single call, and setting the virtual attribute in each to the right value.
If you have more than one field to override, you can write a small solution to create a virtual attribute to each. If you need more on this, just let me know!

Related

Can I list all dependent objects of an object (say, user)?

I have a model and can manually check every (:has_many, :has_one) dependency, but I want some magic like current_user.attributes for records. So when I update model, I don't need to update method.
I tried Reflections, but it returns all theoretical dependencies/connections of model, isn't it? And I need dependent records from DB.
Something like X.where(user_id: #user.id) or #user.dependents
Is it possible?
You can assign required object to model and then
model.class.reflect_on_all_associations.map { |table| model.method(table.name).call }.select(&:any?)
For example:
user = User.first
user.class.reflect_on_all_associations.map { |table| user.method(table.name).call }.select(&:any?)
# returns all associated objects of first user
You can specify result using :has_many, :has_one or :belongs_to as argument of reflect_on_all_associations.
Possibly there is more elegant way, but it works.
TL;DR Don't do this :)
You can do something quite similar using reflections. For example
#user.class.reflections.keys.flat_map { |reflection| me.send(reflection) }
will give you an array with all the objects associated with the user. But what's next?
For almost any real-world logic around this list's members (except the basics that come from AR::Base) you will have to check either a class of an object or use bug-prone try magic - both options are reasonable trade-off sometimes, but in most practical cases I'd prefer less smelly solutions (even if they are a bit more verbose).

Hash getter and setter on ActiveRecord object

I have an ActiveRecord object that was serializing a hash property to one of my database columns. I'd like to get away from this since querying by one of the hash keys is very difficult/not clean. So I've split all the keys of the hash up into separate properties on the model. However, I have a lot of places using this code so in the meantime while I convert everything I'd like to have a property on my ActiveRecord object that is for Rails only (i.e. it doesn't populate back to my database) that wraps up those properties into a hash like it used to be and allows values to be set and get.
So for instance, this is what I used to have:
class MyCls < ActiveRecord::Base
serialize :state, Hash
attr_accessible :id, :mode
I'm getting rid of :state and replace it with 7 different values that made up this hash. But I'd still like to be able to access those values like this: MyObj.state[:obj_num]. Even though I now have obj_num as a property (i.e. MyObj.obj_num). I'm thinking the best way to do this would be to have a state property with a getter and a setter, but I can't quite seem to get the syntax right. For the setter I'd need to support both setting the hash as a whole and setting individual keys.
First to say: I dont think thats the best solution. When you touch this code again in lets say 3 years it will be like "WHAAAAAT HAVE I DONE?"... It whould the best solution to replace all the snippets in your code with other code.
You can prepend the method_missing method of the object after removing this line serialize :state to fetch all calls that want to access the not anymore existing serialized field of the object. Its explained here:
http://blog.enriquez.me/2010/2/21/dont-forget-about-respond-to-when-implementing-method-missing/
Its called metaprogramming. Thats the "rails magic" that makes all the find_by_attribute_name stuff working without defining each of these methods. Can be cool stuff but you need to be very carefull and you need to know what your doing.

How Do I Call An Array Written in My Model

Greeting all
I would like to create an array in my model and then reference it later from a view or a helper. How do I do this?
This is in my Events model. Users can select a lunch type(1,2,3) for the event. Instead of hard-coding sandwich names, which can change, in my view, I thought I would keep the names in one place (model) then reference the name based on the lunch type chosen.
SANDWICHES = { 1 => 'Turkey', 2 => 'Veggie', 3 => 'Roast Beef' }
How do I call this from another script in my app like a view or a helper?
Event.SANDWICHES[1] does not work
event_obj.SANDWICHES[1] does not work
thanks for any help.
What you have there is a constant and you need to access it with Event::SANDWICHES.
What you are describing here is not a Model (in the rails way), it's simply a constant.
If you don't want to create an actual Model with its own database table, you could pull this out into a helper.
Such as fillings_helper.rb
def fillings
%q{Turkey, Veggie, Roast Beef}
end
Then you can use it in your views for a select box by passing in fillings
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-select
You would need to set up a text field in your Event model to accept a string for fillings.
This isn't necessarily the best way from a database normalisation perspective, but it will do what you're asking for.

Order by association field using ActiveRecord

Is it possible to write an ActiveRecord query that sorts by an association field if the association exists, and otherwise sorts by an attribute on the object itself?
Example: I have a Discussion object which has_many :comments. I'd like to display a list of discussions sorted by discussion.latest_comment.created_at. However, some discussions may not have any comments, in which case I would like use their discussion.created_at attribute instead.
The catch is that I need the result to be an ActiveRecord::Relation (for performance reasons, and also because we are using Kaminari [which requires a Relation object]).
The only thing I could think of is to actually create a new field like discussion.latest_comment_at which would be initially populated by discussion.created_at and then updated every time a new comment is posted. However, this doesn't seem very straight-forward from a maintenance perspective (e.g. what happens when a comment gets deleted?).
I don't know of a way to do this through SQL, so I cheated and I have my code set a last_post_at attribute whenever a topic is created.
That way, I can then sort the topics by last_post_at rather than having to query two tables at once.
I've seen other forum systems do it this way too, and it seems like what you're designing is exactly a forum-like system.

Lots of fields in a model, but want to have a public / private attribute for all of them

I have a model where almost every field needs to have a public / private flag (boolean) for each item. At first I thought I'd make a boolean for each field, however, I am not sure if thats the best way of handeling this. Is there a better way? I'm up for all suggestions.
I suppose it would depend on several things, among which would be who would change it and how often it would need to be changed. If this is just configuration that would change rarely, if at all - then I would put it in a configuration file or initializer of some kind:
PUBLIC_FIELDS = %w(field_one, field_two, field_three)
PRIVATE_FIELDS = %w(field_four, field_five, field_six)
If this is something that was going to be dynamic and static to the application with users being able to modify the information regularly, I would opt for a separate model, called field_visibility, with the following fields field_name, visibility. I would load the fields in initially as seed data and then give the user a UI to modify. I would give the model two named scopes:
named_scope :public_fields, :conditions => {:visiblity => 'public'}
named_scope :private_fields, :conditions => {:visiblity => 'private'}
You could of course use a bit field in place of a string. You can also add a table name to the model if this were to stretch to additional models.
Then in the model that this pertains to, you could do a few things to reference back. including named scopes:
named_scope :public_fields, :select => FieldVisiblity.public_fields
individual functions, metaprogramming... This also lends itself to possible enhancements down the road.
I hope this helps!
I would better encapsulate your class by making all your variables private and providing get methods for each variable. This also makes it easier to add variables later on.
You could also use a flagmap (see dm-types how it would work) and an Array in each class which defines the position of the columns in the flagmap. Then overwrite the attribute readers to return nil unless #visible is set to true if the field is marked private via the flag map. Happy bitshifting ;-)

Resources