Comment belongs_to a deleted user. How to associate a "placeholder"? - ruby-on-rails

My comments are placed by users. The Comment belongs_to :user and the User has_many :comments.
But users can be removed. If done, I'd rather not delete their comments, but instead associate their comments with one Dummy user.
I can think of several ways:
On load of a comment, if no associated user is found, create a User in memory with dummy data.
On load of a comment, if no associated user is found, pick a predefined one from the database.
On removal of a comment, associate all the comments with a predefined User in the database; through some post filter.
My feeling says that number one is cleanest; since the other two require a user in the database that will be hardwired in the code. If user 18394 will be that "special" user, I'd need all kinds of safetynets for that special user.

What about soft deleting users instead? Have a boolean field called User.active and set a default scope for User.active = t. When a user gets deleted, set the active field to false, and clear out any personal data.

Related

Rails named has_many with a limit

I want to achieve a has_many association with a x number of records, and the records would be named.
Let's explain that better. In a previous question I asked how to make a text area with a selectable markup language and we reached the conclusion that I needed a separate model, Field which had the multiple fields I needed (language, original and rendered).
Now I want to be able to make a model, let's say User, which had two of these fields. For example: about_me and biography. How would I create those fields every time I create the user, edit them when I edit the user and destroy them when I edit the user? And how would I display them simply writing: User.about_me and User.biography?
Thanks in advance for the answer.
David's solution creates the joint model.
Then you have to include the form of the profile in the User form. You'll have to use accepts_nested_attributes_for method in the User model.
To destroy the profile when user is deleted, add dependent => :destroy to the relationship between the 2 models.
You'll need to use callbacks (http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html).
For example, in your User model, have a after_create callback that will create the requisite fields.
Also,have an after_save callback that checks user.changed? and if it is different, update the fields.

Multiple non-related models in one Rails form

I am building a blog-style application in Rails 3 where multiple users are able to post some news. After the login (which is realized with "Authlogic") the user values are stored in a own model called e.g. "UserSession". The form for the post contains title, content etc. and the username should be stored with a hidden form.
I think that the two models don't need to be related to each other (by that I mean a :has_many - :belongs_to relationship) because there isn't any further usage for that information.
Do I really not need this relation? And how could I realize the form?
For Authlogic is it important to remember that the 'UserSession' does not correspond to any database tables (i.e. you would never use a has_many or has_one 'UserSession'). I think the relationship you are looking for is:
User has many Posts
Blog belongs to User
The reason? It is always a good idea to associate a record with the 'owner' so that the owner can later modify or delete the record. I hope this helps.

Rails Associations: HABTM?

Hey guys, I'm at a deadlock here after thinking about this for too long.
Context: Given the following models:
User
Item
Lock
Here's the scenario: A lock is basically like a 'hold'. A user can place a 'lock' on any given item to signal to the system that the item should not be deleted. Items wont be deleted until the lock is cleared.
Here's the tricky part. The lock is its own model because I want multiple users to be able to lock any given item. So let's say Bob locks an item, one didn't already exist so it creates a lock for that item, and information stating that Bob is currently associated with that lock. John comes and locks the same item, but a lock already exists, so John is simply 'added under' the same lock. The lock won't be removed until all users choose to 'unlock', or disassociate themselves with that lock.
My confusion is how I should model these relationships. A user can of course have many locks, each associated with a different item (since any given item can have at most one lock). The locks themselves can have many users. From the point of view of the item, each item can have one lock associated with many users.
So in other words, I would like to access the information a little something like this:
item.lock.users # get the users 'locking' the item
user.locks # get the items the user is currently 'locking
Perhaps the separate Lock model isn't required, but I figured it would be in order to signify that multiple users can be locking a particular item.
I think what further complicates things is that items are added by users, so I would want to have a way to access the items by a user for example user.items or item.user.
Right now I have:
user has and belongs to many locks
lock has and belongs to many users
user has many items
item belongs to user
item has one lock
lock belongs to item
Does this seem correct?
I think what you're doing will work though you may not have to use the habtm. What if an item can have many locks and can only be deleted when it has no locks. That way you could add a date/reason/comment for each lock by user.
user
has_many :locks
has_many :items
lock
belongs_to :user
belongs_to :item
item
belongs_to :user
has_many :locks
This will still allow you to do user.locks though item.lock.users won't work, but by looking at each lock you'll easily be able to get the users.
item.locks.each do |lock|
puts lock.user
end
You don't need the lock model. You can simply set up a habtm relationship between users and items:
class User < ActiveRecord::Base
has_many :items
has_and_belongs_to_many :locks, :class_name => "Item"
end
User.first.items # => [<#Item>, <#Item>, ...] # Items created by user
User.first.locks # => [<#Item>, <#Item>, ...] # Items locked by user
class Item < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :lock_users, :class_name => "User"
end
Item.first.user # => <#User> # Creator of the item
Item.first.lock_users # => [<#User>, <#User>, ...] # "Lockers" of the item
You'll have to create a join table, of course, and be mindful of what Rails expect the join table to be named. You may be better off specifying the :join_table option for the habtm.
The key here is that relationships in Rails are very flexible. You can have multiple relationships between the two tables; you can have both the 'created by' and the lock relationships, independently of each other. All you have to do is use different names for the relationships.
I can relate to "thinking about this for too long". When that thought creeps into my mind I back away and work on other parts of the code. Relationships seem to reveal themselves over time as they're really a convenience to spare us writing a bunch of code. They're not essential, so, at least during the development phase, we can postpone the declaration of the relationships and see what we need a bit later.
Yeah, we're supposed to always know ahead of time according to the pragmatists, but in real life we're often having to use our common sense and experience and build a working prototype, then fine tune it. It's during that fine-tuning stage I tweak my relationships that weren't exactly clear before, and adjust my code.
Sniff... sniff... jeez, now my bosses know I'm not perfect... sniff....
Back to the question at hand: Normally, for locks to prevent accidental (or on purpose) deletion, I create a boolean field in my main table and if that record should be purged set it to true. For what you're doing I'd probably get rid of the flag field altogether and have a separate table that is the IDs of the records to lock, along with the user's IDs who want to keep the record. Delete those user's records if/when they think it's time to delete the record. When it's time to do some purging I'd check against that table. Something similar to:
delete from table1 where id not in (select distinct(table1_id) from table2)
The thing I don't like about it is there's potential to have another table full of "keep this record" records, and that's when I add another table for users to terminate who can't decide what things need to be deleted.

Ruby on Rails - Optional Associations?

I would like to allow users to write comments on a site. If they are registered users their username is displayed with the comment, otherwise allow them to type in a name which is displayed instead.
I was going to create a default anonymous user in the database and link every non-registered comment to that user. Would there be a better way to do it?
Any advice appreciated.
Thanks.
The problem with creating an anonymous user is then you need to check if a comment was made by a "real" user, or an anonymous one when displaying the name, so that introduces complexity. Plus, if you have a way of viewing their profile page, which may include posting history, you'd need to exclude the anonymous user with an exception.
Generally it's better to have a column on your comments which represents the user's visible name, and just show that if provided, or the registered user's name otherwise. For instance, your view helper might look like this:
class Comment < ActiveRecord::Base
belongs_to :user
def user_name
self.anonymous_name or (self.user and self.user.name) or 'Anonymous'
end
end
This will display the contents of the anonymous_name field of the Comment record, or the user's name if a user is assigned, or 'Anonymous' as a last-ditch effort to show something.
Sometimes it's advantageous to actually de-normalize a lot of the database when dealing with large numbers of comments so you don't have to load in the user table via a join simply to display a name. Populating this field with the user's name, even if they're not anonymous, may help with this, though it does mean these values need to be updated when a username changes, presuming that's even possible.
I think you can make user_id on your comment model nullable since you want to allow non registered users to add comments as well. As far as adding names for the non registered users are concerned, there are two options for that
option 1. Add a column on Comment model and name it like anonymous_user where you will store names of non registered users
option 2. Create a another model AnonymousCommentor with name and comment_id attributes.
If you are going to use anonymous users for other things as well apart from comment in your application then you can make it polymorphic and use a suitable name like AnonymousUser instead of AnonymousCommentor

Data Modeling Question for Rails

I have the following entities.
User
Event
Expense
Guest
A User is someone that is registered with my site. An event is something that a specific user can create and then invite people to (other users). An expense is created by a specific user for a specific event and can be associated with other users/guests of the event (like user A bought something for user B and user C and guest D). A guest is also created by a specific user for a specific event but once created for the event, the other users associated with that event can see the guest. A guest will never actually log into the system...it is just a placeholder for people that may have attended an event but whom are not registered on the site.
I am trying to wrap my head around the has_many and belongs_to attributes of these entities.
It is almost like in my many-to-many relationship tables I need another column which identifies the "type" of person (user or guest) so I can join properly to pull in names, etc. from the users and guests tables accordingly.
I have thought about creating a flag in the users table that says whether the record is a guest (and therefore not require that guest to register with the site, login, etc.) but that doesn't seem very clean.
Any thoughts are greatly appreciated.
Thanks!
Thomas
This sounds to me like you're naturally leaning towards what is called a polymorphic association. It might be useful for you to have a look at this Railscast by Ryan Bates: Polymorphic Associations
I agree with Gav Polymorphic just one table people with a column type and tada
class Person < ActiveRecord:Base
#methods and associations all people have
end
class User < Person
#methods and associations specific to users
end
class Guest < Person
#methods and associations specific to guests
end

Resources