In Part 1 I left the project where I could have a user (the invitor) invite another user (the invitee) to have access to the "invitor's" posts. Additionally I could allow the "invitee" to change their email when they first singed up.
In Part 2 I finish up the discovery of using DeviseInvitable by accomplishing the following:
- Fix some overlooked problems
- Add ability to invite an existing user
Fix Problems
I realized after I finished Part 1, that the project I posted had a needless dependency on PostgreSQL.
My goal for this discussion was to better learn DeviseInvitable, not database setup. So I switched the database dependency back to the default "sqlite3" gem the "stock" rails app had when I first created it and updated the "database.yml" file.
To make this work, I also had to change the definitions for the "current_sign_in_ip" and "last_sign_in_ip" fields in the original User's migration as SQLite does not support PostgreSQL's proprietary "inet" data type. So these two lines (in {date}_devise_create_users.rb
):
t.inet :current_sign_in_ip
t.inet :last_sign_in_ip
became:
t.string :current_sign_in_ip
t.string :last_sign_in_ip
The second problem I realized I had, was I had forgotten to limit posts by a user to only that user and their friends.
Without that "feature" it kind of defeated the purpose of the test app in the first place. So to fix that I added a "has_many" relationship to posts from the user.
I first created the migration and ran it:
rails g migration add_references_to_tasks user:references
rake db:migrate
I then added the requisite has_many :posts
declaration to the User class and the belongs_to :user
to the Post class.
Next, I had to add the following line to the PostsController#create
method:
current_user.posts << @post
To ensure a user saw all their posts and those of their friends I changed the default implementation of the PostsController#index
method to be this:
def index
# retrieve all posts created by me
sql = "user_id = #{current_user.id}"
# retrieve all posts created by my friends
friend_ids = current_user.friends.ids
friend_ids_string = friend_ids.join(", ")
if (friend_ids_string.length > 0)
sql = sql + " or user_id in (#{friend_ids_string})"
end
@posts = Post.where("#{sql}").order(:created_at)
end
To be honest, at this point I thought I had the posts correctly restricted, which I did, but in testing I realized that when I created the friend_relationship in order for both sides to see the posts of the other I actually needed to create two friend_relationships. One for the user who just signed up and one for the user who did the inviting. I added that extra line of code to the User#add_friend
method. I won't list that here, you can check the posted code out to see it.
With all that done a user can now login, create posts, invite a second user, and when that invitee sign's up they can create posts and both users can see the posts of each other as well as their own posts.
With that done I could now deal with my final question:
How can a user invite an existing user to see be their friend?
Inviting an existing user
The last question boils down to how can an existing user be invited?
The key to this question is to understand how DeviseInvitable handles inviting an existing user.
In that case no invitation token is generated or stored in the database and in fact all the code really needs to do is execute the code that would normally happen if a non existing user was invited and accepted the invitation.
To do this I changed PostsControler#invite
to this:
def invite
@userToInvite = User.find_by(:email => params['email'])
@invitations = current_user.invitations
if (@userToInvite != nil)
current_user.friend_relationships.create(:friend => @userToInvite)
@userToInvite.friend_relationships.create(:friend => current_user)
else
@userToInvite = User.invite!({:email => params['email'], :skip_invitation => true}, current_user)
end
@userToInvite
end
The change here is on lines 5 and 6. If we find the invitee already exists then we just set up the two friend relationships.
To test this, I started the app, signed up a new user, logged that user out, then logged in as the original user and invited the user I had just created.
When logged back in as the invited user they could now see the posts of their invitor.
At this point, I need to mention that this isn't how this feature will be implemented in the production app I am exploring this for.
In that app I will store off the fact the user was invited and possibly send them an email notifying them they were invited to be a friend. But, I will not automatically set up the relationship. Only if the invitee "acknowledges" the invitation will I actually create the relationships.
So that's it. All the questions I had have been answered. I now know how to:
- Invite an outside user to the app
- Collect other information when an invitee sign's up
- Invite an existing user
You can view my first post on this subject here. I also updated the example project which can be found here.
Till next time.
No comments:
Post a Comment