Design question: Aliases for a Location model (Rails) - ruby-on-rails

This is more of a general design question, but it will be implemented in RoR to which I am very much a newcomer. Also, I think this is my first question so please be gentle :)
The scenario is:
I have an Asset model. Each asset is located in a particular room, so I would also like a one-to-many relationship with a Location model. Simple enough. However, some rooms (Locations) also go by an alias (eg. 123 is aka Library). When a user wants to update information about a particular Asset, I would like them to be able to just search without worrying about whether they know the exact room number, and be shown a list of assets in that room.
To clarify, there could be more than one alias.
So the question is:
Would you recommend an Alias model for which a Location would have a one-to-many relationship? Or, would a self-referential (sort-of hierarchical) association be better? Or something else maybe? From what I can envisage, the former would require querying columns on different tables for the same sort of information, and the latter just doesn't seem right (an Alias is not the same as a Location).

This might be a good area for using the tagging plugin acts-as-taggable-on:
https://github.com/mbleigh/acts-as-taggable-on
In your model you can do:
class Location < ActiveRecord::Base
acts_as_taggable_on :aliases
end
Then in your controller do:
Location.tagged_with("library", :on => :aliases)

Related

How to setup my article relationship

I want to make a article model.
A article belongs_to country
A article belongs_to region
A article belongs_to accomodation
So i want create listing like...give me articles from region X, give me articles from accomodation X.
The url structure looks like this:
/en/italy/articles
/en/italy/tuscany/articles
/en/italy/tuscany/accomodation_x/articles
ect
It is possibly in the a future that article has nothing todo with a accomodation, country or accomodation. By example company news ect
The url structure looks like this:
/en/articles
And on my homepage i want a show all new articles, with different paths. Point root_path of articles but also to the country_region_articles paths.
What is the best approach to setup the db relationsships?
Thanks..
remco
You might want to check these two casts too. On tagging and virtual attributes:
http://railscasts.com/episodes/167-more-on-virtual-attributes
http://railscasts.com/episodes/382-tagging
I can't see any content strategy in your question so my answer may be biased.
In common sense an article may be about an accommodation or completely not. It may be related to a region without specific accommodation. Or it may be about a country with nothing to do with either region or accommodation.
In this case, tagging would be much better than hard association.
Another point is, either association or tagging can has nothing to do with URL. You are not required to use nested url with association.

Rails: Finding models with missing has_one records

If model User has_one Profile, is there a simple way to find all users who have no profile without a custom query (eg NOT User.where('profile_id IS NULL')) or processing it in the app?
Since the association between User and Profile is already known to Rails I don't want to restate it. I want to keep this DRY. The actual connection between the models is more complex than this simple example (uses keys and class name) and may change in the future.
As #tadman & #antonk already said, you probably want to use scope:
scope :without_profile, where(profile_id: nil)
EDIT:
To answer #David Mauricio's question: you could use it by calling User.without_profile, to return the AR association of all users with a nil :profile_id.
#DriverDan : then I'm really unsure what you're asking for. Ask another question with more details, and we can try to answer it!

Solution to insert cross-hyperlinks of Rails objects inside text attribute (as HTML)

I am working at a web app in Rails that behaves much like a CMS: there are articles, which have a text attribute that contains links to other articles (or other object classes). I'm currently storing the attribute as HTML.
Is there any good way to model those links in a way that is relative easy to change, and contain the reference to the object id, instead of the absolute url?
One of the solutons I was thinking was to use some kind of special mark-up, such as:
[link_to "Text for the link", Article:12]
where 12 is the id of the article it links to. This mark-up will be parsed when the text is rendered.
The downside of this is that I have to hack into TinyMCE (the editor I'm thinking of using to edit the HTML) so that it can insert links to other objects, by accessing the database and automatically assigning the object type and ID (the person who's editing the texts doesn't know the id's).
Is there any simple solution to this?
Or should I stick to using absolute urls (which, besides maintenance issues, is annoying in development, as they will always point to production and that is confusing for me)?
Additionally, does anyone have similar examples in other languages (php, Wordpress, other CMS, etc) that tackle this problem in a nice way? I'm thinking, this is pretty vital in CMS, and can reduce a lot of man hours if a nice system can handle all those links.
EDIT:
Another possible solution that I'm thinking about is letting the person copy the link of the article directly in the code, but it should, upon submission, generate the correct association id and make it so that if the url structure changes, the link is always up-to-date. I'd like to hear your opinions and experience with this approach, if you have tried it.
The challenge with this approach is parsing the link with Rails and finding out that it points to an Article, and that article has the id ##. Then I have to insert a shortcode that will always translate, upon parsing and rendering, to an actual link to that article.
I found a method that could make this feasible:
Rails.application.routes.recognize_path
But there may be some caveats that I don't see right now...
EDIT no. 2
I also want to specify that I chose CKEditor as the content editor, but I will consider other ones if there are clearer advantages.
I have built something similar using a shortcode system which would allow me to call specific methods on the model and replace the shortcode in the text:
Helper
def parse_shortcode(model)
text = model.text
text.gsub(/(\[#!\s?\w+\])/i) do |match|
result = model.try(match)
result.nil? '' : link_to(result[:text], result[:url])
end
end
Model
def contact_link
{ :text => self.name, :url => self.url }
end
View
<%= parse_shortcode(#article) %>
I haven't tested the above code and it is obviously a bit simplified but it explains my thought process behind this.
EDIT: Just to clarify my above example uses an invented shortcode syntax of [#! method]
An article can have many related_articles and at the same time this article can be related by many other articles, so it is best to model this as a many-to-many relationship.
One way to define this type of relationship in Rails is has_many :through.
To use has_many :through you have to create a join model, perhaps call it ArticleRelation. This model will have two fields, an article_id that represents the current article and a related_article_id that represents the article who’s being referred as related.
class Article < AR::Base
has_many :article_relations
has_many :related_articles, :through => :article_relations
end
class ArticleRelation < AR::Base
belongs_to :article
belongs_to :article_relation, :class_name => 'Article'
end
When creating self-referential relationships it’s important to remember that you’re only creating one side of the relationship. Although article_1 might list article_2 as related, there is no way to for article_2 to list article_1 as related. You'd need two ArticleRelation records to create a mutual relationship.
It’s difficult to think up appropriate names to define another side of the relationship so you can prefix both with the word “inverse” to give inverse_article_relations and inverse_related_articles. You also need to specify some additional options to make the relationships work. For inverse_article_relations you’ll have to specify the name of the other model as it can’t be inferred from the relationship name and you’ll also have to define the foreign key as related_article_id. For the inverse_related_articles relationship you need to specify the source as articles, as again it cannot be inferred from the name of the relationship.
has_many :inverse_article_relations, :class_name => "ArticleRelation", :foreign_key => "related_article_id"
has_many :inverse_related_articles, :through => :inverse_article_relations, :source => :article
Test it out, this should work for you per current requirement.
A solution I've seen in a lot of other CMSs is a combination of custom file browser in TinyMCE and page rewriting (similar to freakyDaz's answer).
TinyMCE has documentation and example code for implementing a custom browser. You'll have to provide the backend pieces, of course.
CKEditor has documentation for a similar feature as well.
Have your backend implementation return something that's easy to parse for the URLs (urlfor:Article:12, for instance), then have your rendering code replace those with actual URLs.
I just thought of another possible solution for the use case:
The admin user specifies the relationships before they edit the text (using Chosen.js, this can be done in a user-friendly way).
Then the person either submits the form to save the model or it can be done asynchronously.
When the relationships are saved, a shortcode is generated and displayed for each of them, and that short-code can easily be pasted in the text.
When displaying the text in the front-end, the text will be parsed for the shortcode, in a similar way to what #freakyDaz is suggesting.
In this way, I don't have to hack or create custom actions in the editor. I think it's a pretty pragmatical approach, but I'd like to hear your opinions. Of course, the admin who's making the text should be educated to follow the process in that order, but in my case very few persons can be admins (1 or 2), so it's manageable.

Rails blog and post linking

I have a rails app that works almost like a blog, and I use a tagging system to categorize the posts.
I need to add to some of the posts something similar to a "related posts" feature.
So for example if post 1 is related to post 4, at the end of the show action for post one I want to render an image of post 4 and at the same time at the end of post 4 an image of post 1.
My idea is to create a "link" model that has a HABTM relations with the post model, but I'm not sure if a "post" has many "links" trough "linkings" would be better.
Both of the ideas seem to have the same result, so which approach should I prefer?
HABTM is by nature very simple, with just a table of foreign key pairs joining models.
Typically has_many through is used when you need to add additional attributes to that join relation, and/or when you need to treat the joins as their own model.
In your case, for example, you might want the links to appear in the order that they were created. For this to happen you'd need to store the create timestamp on the relationship. For this, the simple HABTM join table is not enough, so you switch to has_many through and create a Linking model to encapsulate the join.
To continue the example, you might also make Linking a first-class resource, and have a page where you can edit/add/remove them separately from either linked Post.
Personally I've always used has_many through in the majority of cases. It just feels cleaner to me (no auto-naming table magic to accept or override, and the linking is more visible), and I find that very often, join relationships do deserve to be first class citizens.

MongoDB Embedded Documents / Documents with Rails

I've recently begun playing around with MongoDB on Rails through use of the MongoMapper gem. I was wondering if there is some sort of way to have a class/object/collection be both a Document as well as an Embedded Document. I want the same entity to be both included/embedded in other documents, and also be able to exist on its own as an object.
Is this possible? Am I tackling this problem the wrong way? Any discussion/advice would be greatly appreciated as resources on the web seem low for this stuff right now.
I have a very similar usecase and the solition was to have (using your entity names):
a collection with People
a embedded model BusinessPerson that belongs_to_related :person
a collection with Businesses that embeds_many :busiess_people
The idea behind this was that I have extra fields in BusinessPerson that may not apply if the Person also run a different business. Let's say the role in that business, an email address or the share of it.
No you might say getting the business a person might look hard, but it isn't:
class Person
def businesses
Business.where('business_people._id' => self.id)
end
end

Resources