rails alternative to enum and view integration - html

rails doesn't offer ENUM types, but I do need a data member which can accept only five values. Moreover, I want it to be integrated automatically with the Rails Forms Helper: select_tag.
What's the right solution to my situation?
P.S, I'd rather not to use external plugins, if built-in and neat solution exist.

I keep functionality like this as close to where it's used as possible.
If the values are used by a single model, just keep them in the model, e.g., if users have certain possible types, and only those types, it might look something like:
class User < ActiveRecord::Base
TYPES = %w{guest, paid, admin}
# Plus validation on the `type` field.
# Maybe plus a setter override that also validates.
end
When you need to refer to those types elsewhere, like as allowable values in a select:
User::TYPES
There are a number of valuable tweaks around this, like providing decorators to make them "human readable" (capitalized, spaced, whatever) or metaprogramming methods to allow things like:
user.is_guest? # Or...
user.make_guest! # Or...
user.guest!
I use my own small gem for this functionality because it's often the case that a full-blown association is just too much and provides no value. It allows things like:
class User < ActiveRecord::Base
simple_enum :user_type, %w{guest, paid, admin}
end

Using the tip from this blog post, which offers a very simple approach.
You can set in on your model and then use it on your controller or views.
In this case it will map the status with integers.
STATUS = { pending: 0, active: 1, inactive: 2, deleted: 3 }
def status
STATUS.key(read_attribute(:status))
end
def status=(s)
write_attribute(:status, STATUS[s])
end

Rails 4.1 has enums. I just upgraded to the beta and it's working like a charm!
http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html
I tried active_enum gem, which is great, but it's not compatible with rails 4. The solution from Paulo works pretty well and you can extract the enum into a concern if you want, but it just started getting too heavy for me so I rather upgraded!

You can easily define the Enum as a helper in ApplicationHelper
class ApplicationHelper
def select_range
%w{"a", "b", "c", "d", "e"}
end
end
Then in view you can call select_range freely.

Related

ActiveModelSerializers Polymorphic Json

Been wrestling with trying to get polymorphic serializers working and testing data via rspec. Just upgraded to 0.10+
I found this post, which makes a lot of sense, and does give me a entry into generating the serializations, however, when doing it for polymorphs, I never get the type and id properly named (expecting to see asset_id and asset_type nested)
{:id=>1,
:label=>"Today I feel amazing!",
:position=>0,
:status=>"active",
:media_container_id=>1,
:asset=>
{:id=>4
Test ActiveModel::Serializer classes with Rspec
class MediaSerializer < ApplicationSerializer
attributes :id,
:label,
has_one :asset, polymorphic: true
end
I noticed that the tests dont even seem to properly add the polymorphic identifiers either (ie asset_id, asset_type -- or in the test case imageable_id, imageable_type)
https://github.com/rails-api/active_model_serializers/commit/045fa9bc072a04f5a94d23f3d955e49bdaba74a1#diff-c3565d7d6d40da1b2bf75e13eb8e6afbR36
If I go straight up MediaSerialzer.new(media) I can poke at the .associations, but I cant seem to get them to render as if I was generating a full payload
From the docs
https://github.com/rails-api/active_model_serializers
serializer_options = {}
serializer = SomeSerializer.new(resource, serializer_options)
serializer.attributes
serializer.associations
Im pretty sure Im missing something/doing something wrong - any guidance would be great.
Thanks
It isn't easy to get the effect you are looking for, but it is possible.
You can access the hash generated by the serializer by overriding the associations method.
class MediaSerializer < ApplicationSerializer
attributes :id,
:label,
has_one :asset, polymorphic: true
def associations details
data = super
data[:asset] = relabel_asset(data[:asset])
data
end
def relabel_asset asset
labelled_asset = {}
asset.keys.each do |k|
labelled_asset["asset_#{k}"] = asset[k];
end
labelled_asset
end
end
I learnt alot about ActiveModelSerializer to get the hang of this! I referred to Ryan Bates' podcast on the topic:
http://railscasts.com/episodes/409-active-model-serializers
In there he describes how you can override the attributes method and call super to get access to the hash generated by the serializer. I guessed I could do the same trick for the associations method mentioned in your post. From there it takes a little bit of Ruby to replace all the keys, but, if I have understood correctly what you require, it is technically possible.
Hope that helps!

Multiple types for each record in Neo4j.rb

I have a database currently represented as a set of YAML files (one record per file). I would like to port it into Neo4j. Each record has a property "type" which stores an array of types. I would like to have a module (that includes ActiveNode) for each type. Each node object would then extend the modules corresponding to its types. The only way I can think of to implement this with neo4j.rb is to generate a class for each existing combination of types and include the corresponding type modules in the class. Is there some better way to accomplish this?
More concrete examples might help. Is there a natural hierarchy to the types?
Class hierarchy for multiple labels has been supported for a while, but I just put in some changes to the master branch in the last couple of days to make it work more smoothly. You should be able to do something like this:
class Person
include Neo4j::ActiveNode
end
class Author < Person
end
class Collaborator < Person
end
class Software
include Neo4j::ActiveNode
end
class Application < Software
end
class Library < Software
end
If you did ChildType.create it would create a node with both the ParentType and ChildType labels. If a query loads a node with both labels, the ChildType model class will be used.
We've also talked about the ability to load modules to do multiple labels, though we weren't able to think of a good example, so I'd welcome one.

Paper form to database

I am doing a Rails 3 app that replaces a paper form for a company. The paper form spans two pages and contains a LOT of fields, checkboxes, drop downs, etc.
I am wondering how to model that in the DB - one approach is to just create a field in the DB for every field on the form (normalized of course). That will make it somewhat difficult to ad or remove fileds since a migration will be needed. An other approach is to do some kind of key/value store (no - MongoDB/CouchDB is not an option - MySQL is required). Doing key/value will be very flexible but will be a pain to query. And it will directly work against ActiveRecord?
Anyone have a great solution for this?
Regards,
Jacob
I would recommend that you model the most common attributes as separate database fields. Once you have setup as many fields as possible then fall back to using a key-value setup for your pseudo-random attributes. I'd recommend a simple approach of storing a Hash through the ActiveRecord method serialize. For example:
class TPS < ActiveRecord::Base
serialize :custom, Hash
end
#tps = TPS.create(:name => "Kevin", :ssn => "123-456-789", :custom => { :abc => 'ABC', :def => )'DEF' })
#tps.name # Kevin
#tps.ssn # 123-456-789
#tps.custom[:abc] # ABC
#tps.custom[:def] # DEF
If your form is fairly static, go ahead and make a model for it, that's a reasonable approach even if it seems rather rudimentary. It's not your fault the form is so complicated, you're just coming up with a solution that takes that into account. Migrations to make adjustments to this are really simple to implement and easy to understand.
Splitting it up into a key/value version would be better but would take a lot more engineering. If you expect that this form will be subject to frequent and radical revisions it may make more sense to build for the future in this regard. You can see an example of the sort of form-builder you might want to construct at something like WuFoo but of course building form builders is not to be taken lightly.

Deal with undefined values in code or in the template?

I'm writing a web application (in Python, not that it matters). One of the features is that people can leave comments on things. I have a class for comments, basically like so:
class Comment:
user = ...
# other stuff
where user is an instance of another class,
class User:
name = ...
# other stuff
And of course in my template, I have
<div>${comment.user.name}</div>
Problem: Let's say I allow people to post comments anonymously. In that case comment.user is None (undefined), and of course accessing comment.user.name is going to raise an error. What's the best way to deal with that? I see three possibilities:
Use a conditional in the template to test for that case and display something different. This is the most versatile solution, since I can change the way anonymous comments are displayed to, say, "Posted anonymously" (instead of "Posted by ..."), but I've often been told that templates should be mindless display machines and not include logic like that. Also, other people might wind up writing alternate templates for the same application, and I feel like I should be making things as easy as possible for the template writer.
Implement an accessor method for the user property of a Comment that returns a dummy user object when the real user is undefined. This dummy object would have user.name = 'Anonymous' or something like that and so the template could access it and print its name with no error.
Put an actual record in my database corresponding to a user with user.name = Anonymous (or something like that), and just assign that user to any comment posted when nobody's logged in. I know I've seen some real-world systems that operate this way. (phpBB?)
Is there a prevailing wisdom among people who write these sorts of systems about which of these (or some other solution) is the best? Any pitfalls I should watch out for if I go one way vs. another? Whoever gives the best explanation gets the checkmark.
I'd go with the first option, using an if switch in the template.
Consider the case of localization: You'll possibly have different templates for each language. You can easily localize the "anonymous" case in the template itself.
Also, the data model should have nothing to do with the output side. What would you do in the rest of the code if you wanted to test whether a user has a name or not? Check for == 'Anonymous' each time?
The template should indeed only be concerned with outputting data, but that doesn't mean it has to consist solely of output statements. You usually have some sort of if user is logged in, display "Logout", otherwise display "Register" and "Login" case in the templates. It's almost impossible to avoid these.
Personally, I like for clean code, and agree that templates should not have major logic. So in my implementations I make sure that all values have "safe" default values, typically a blank string, pointer to a base class or equivalent. That allows for two major improvements to the code, first that you don't have to constantly test for null or missing values, and you can output default values without too much logic in your display templates.
So in your situation, making a default pointer to a base value sounds like the best solution.
Your 3rd option: Create a regular User entity that represents an anonymous user.
I'm not a fan of None for database integrity reasons.

Can we change the way Rails writes HTML IDs and such?

I just started checking out Wordpress' CSS Architecture to study a system that's established and pretty powerful to learn better HTML habits. I've noticed they use all hyphens - (post-554 for example), while Rails uses underscores _ (post_554 for example). I'm wondering if there's some setting to customize this in Rails, something like ActionView::Template.word_boundary = "-".
Is there? Not that it really matters, just trying to learn why people do things the way they do.
:)
You can't change se separator. It is hard-coded into Rails.
For example, post_554 is generated by the dom_id helper, which internally relies on the RecordIdentifier class.
Here's the definition.
def dom_id(record, prefix = nil)
if record_id = record.id
"#{dom_class(record, prefix)}#{JOIN}#{record_id}"
else
dom_class(record, prefix || NEW)
end
end
The separator, the JOIN constant, is defined as freezed String so you can't change it.
module RecordIdentifier
extend self
JOIN = '_'.freeze
NEW = 'new'.freeze
There are two ways to change it:
Create your own helper (suggested)
Overwrite the existing methods/helpers with your own implementations (not suggested)
There are also some technical restrictions that explain the reason behind this choice, mainly tied to the language behind Rails.
For instance, talking about symbols
:post_554 # valid symbol
:post-554 # invalid symbol
:"post-554" # valid symbol
Using - would probably require a less cleaner approach to Ruby.
Personally, I prefer using - rather than _ and I tend to avoid standard Rails helpers unless strictly required.