Reputation: 4403
I'm modeling my User model and adding profile attributes.
I'm looking to add a set of social URLs for the user, starting with about 3 or 4 options and possibly growing to more than 15. It would be very easy for me to just create a separate attribute on the User model for every URL, and then run through them all separately for the profile page. Although this seems like it might be redundant, would this be inappropriate or should I go ahead since the attributes just store a simple string?
If I shouldn't load them all onto the User model:
What would be the best way to go about doing this with a separate model? Any how would I be able to grab all the social urls a user has created in an @social_urls array?
I'm also looking to associate a specific thumbnail image with each website URL to be displayed with the @social_urls.each do block. I'm confused on how I would call dynamically to the correct image.
Thanks so much for any help or insight.
Edit: would this work to attach a html class with the social site name? and then create a thumbnail using css?
# In erb or (better) a helper
<% User::SOCIAL_SYSTEMS.each do |social_system|
url = @user.send(social_system)
if url %>
<p><a href="<%= url %>" class="<%=User::SOCIAL_SYSTEM_NAMES[social_system]%>"><%=
User::SOCIAL_SYSTEM_NAMES[social_system] %></a></p>
<% end
end %>
Upvotes: 2
Views: 460
Reputation: 33732
Do you really need an extra model for that?
if you have to store a growing number of URL for social networking sites or other web-sites, you could do the following:
1) define a migration to add a text column :social_sites
to your User model
class AddSorialSitesToUsers < ActiveRecord::Migration
def self.up
add_column :users, :social_sites, :text
end
def self.down
remove_column :users, :social_sites
end
end
2) define the :social_sites attribute as to be serialized
class User < ActiveRecord::Base
serialize :social_sites
end
3) Then assign a Hash or an OrderedHash to user.social_sites
and save the record..
u = User.find(1)
u.social_sites = {:facebook => 'http://facebook.com/somebody', :twitter => "http://twitter.com/somebody", ...}
because it's a Hash, you can assign as many different Service names as keys as you like.. and then later iterate over the Hash keys to retrieve them...or directly access them with the name of the Site e.g.:
u = User.find(1)
puts u.social_sites[:facebook]
puts u.social_sites[:twitter]
...
Enhancement:
If you want to store more than just the URL for each site, you could use nested hashes as follows:
u.social_sites = {:facebook => {:url => "http://facebook.com/username", :icon => "url-or-filename-to-the-icon"} ,
:twitter => {:url => "http://twitter.com/username", :icon => "url-or-filename-to-the-icon"}
}
Rails will serialize the Hash(es) into the single attribute :social_sites, and when you access it, it will unserialize it -- you can just access it as any other Hash
u = User.find(1)
puts u.social_sites[:facebook][:url]
=> "http://facebook.com/username"
puts u.social_sites[:facebook][:icon]
=> "url-or-filename-to-the-icon"
hope this helps
Upvotes: 1
Reputation: 49104
Creating additional attributes on the User model for independent facts (the social urls) is fine.
Or you could have another two models just for social urls with structure
SocialUrl
id
user_id
social_system_id
value
SocialSystem
id
name # name of the social system ("Google +", "Facebook", etc)
But no need for the additional complexity of the two extra tables unless you really see a value.
Re:
running through them all (the social url attributes)
You can (and should) create helper methods for your User model. Eg, you can have the names of the social attributes as a CONST array and then use #send to retrieve all their values.
Added The tradeoffs between the two styles (either using the User model or creating two additional models)--
In terms of space, db storage is so cheap that it makes no difference. -- Ie the User model style is sparser storage of the data.
I think I would focus on the main part of my app and just use the User model. Simpler and sweeter.
Added Re comments:
For the thumbnail, paperclip or similar is the way to go. -- It does create an additional model and table, but the plugin handles all the details.
For showing the urls, you'd use a helper or two. Eg
User model
facebook_url string
google_plus_url
# Constants defined in User model
SOCIAL_SYSTEMS = ['facebook_url', 'google_plus_url']
SOCIAL_SYSTEM_NAMES = {'facebook_url' => 'Facebook',
'google_plus_url' => 'Google +'}
# In erb or (better) a helper
<% User::SOCIAL_SYSTEMS.each do |social_system|
url = @user.send(social_system)
if url %>
<p><a href="<%= url %>"><%=
User::SOCIAL_SYSTEM_NAMES[social_system] %></a></p>
<% end
end %>
Added ps If you need to store more than one fact per social system (eg url for the profile from the social system plus the person's latest score from the social system), then I would go for the additional tables. But if you only need a single fact (eg the person's profile url), then adding to the user model is fine. (imho)
Upvotes: 1
Reputation: 5370
you probably want to have one model to store the urls for each user, then another model to manage the thumbnails for each site. unless you want personal icons for each user, in which case you will probably include the has_attached_file on the User model rather than making a SocialSite model. paperclip is the prevailing attachment gem for rails, that's where the has_attached_file method comes from.
class User < ActiveRecord::Base
has_many :social_urls
end
class SocialUrl < ActiveRecord::Base
belongs_to :user
belongs_to :social_site
end
class SocialSite < ActiveRecord::Base
has_attached_file :thumbnail
has_many :social_urls
end
Upvotes: 1