Cool video and very clear explanations !
Maybe you can give me a hint on how you would deal with a not so different event management app I'm working on :
User manage its Collaborators like on its phone, meaning full control on Collaborator profiles, and add them to an Event. Two dedicated models are used since Collaborator isn't unique (many User can create a Collaborator which is the same person). The thing is a User is notified of each event with a Collaborator that share the same email, and can choose to take control of it (Collaborator become User). This is the only way I found to have a fully working app before all collaborators joined it as user. It works, but I'm kind of stuck when, on a project, I have to loop through User and Collaborator to show the Event team efficiently. Is there a good way to do this ? Thank you for your very helpful advices
Great stuff. Probably saved me a lot of digging around time. Thanks.
Would have liked to see some aspect of testing addressed. I have come to appreciate good tests, and am still getting comfortable with good testing habits and strategies. I really like how you show real-world stumbling blocks and how to navigate them well. Seeing similar struggle and success with testing would be helpful for me.
I do see devise has some example tests posted, so maybe those are enough to get me going.
I am using rails 4 and got the error below. Any ideas what I am doing wrong? I used the attr_accessor :email in the User.rb model. I have that feeling that I missed something really simple but I am having a brain freeze LOL
NameError in TeamsController#create
undefined local variable or method `email' for #<teamuser:0x007fcef90e37b8>
Extracted source (around line #8):
existing_user = User.find_by(email: email)
self.user = if existing_user.present?
Awesome episode as usual Chris.
How would you modify this to do a single click invite? i.e. say you are looking through a list of users and you want to "invite them" to your project or w/e, how would you do that?
Just create a new action on ProjectUsers controller, pass the email associated with that link that was pressed and then execute `User.invite!`?
The reason I am asking is that I was trying to pass params to the devise_invitable controller and it seems to be more tricky than you would expect it to be on the surface, so I am trying to explore other ways to do do what i am trying to do.
Yeah exactly. I would create my own controller and pass over the user_id which can then look up the user and associate them. Since the user might already have an account, you might just send them an email notice saying they now have access rather than an invite since they already have an account. You could also do an approval process there before it's finally accepted, kind of up to you.
Chris, was able to get emails sent to already-existing users this way below from the ProjectUser model
def set_user_id existing_user = User.find_by(email: email) self.user = if existing_user.present? existing_user else User.invite!(email: email) end if existing_user.present? InviteMailer.existing_user_invite(email).deliver end
About your post here about creating a separate controller, is there a better way to deal with existing users and identify project params? I don't think you can do so from the model here above so assuming that's why you said do it from controller. But issue I have or misunderstanding is how to invite both nonexisting users (new users) and already existing users from the same form input so you wouldn't have to set up two different ones - one for new devise invitable users and a separate one for already-existing users. Seems unnecessary or confusing to users. Tried to overried the devise controller but kind of confusing here and doesn't act as expected from the devise action that is there to invite already existing users. Tried to add it from their documentation but only messes up other things here I'm guessing because of the model setup and inheritance issues. Any quick solution so can send send projectuser or project params to the already-existing user in the email? Thanks a lot.
Chris great episode, thank you so much! One question, everything works great on my end. But, the emails don't actually reach their destinations. Is that because we are in development or do we need to have something extra installed in our app? Thanks mate!
If you've got a real Actionmailer config setup to hit a real smtp server, you can have it send real emails in development. If they aren't arriving, then you will want to double check your configuration to make sure that it's authenticating correctly and you see the emails being sent from your email provider logs.
If you want add "remove user" functionality, here is an example.
In project_users_controller.rb :
redirect_to projects_path, notice: "Member removed"
In projects/show.html.erb :
<% @project.project_users.each do |project_user| %>
<div><%= project_user.user.email %>
<td><%= link_to "Remove member",
project_project_user_path(@project, project_user), method: :delete %></td></div>
<% end %>
The video seems different then the text. I get an error when following the text. When we make the edit to app/views/projects/show.html.erb. I also was getting an error when I followed the video alone. I had to combine what was in the text and video to make it to where I am at now(still not done). Can we get a repo or an update on this? I actually joined for this very lesson.
If I follow the text I get this error:
NoMethodError in Projects#show, undefined method `email' for #
Chris thanks for this great series. If you wanted to allow some projects to be publicly viewable (i.e. not just for invited people who get invited through devise invitable), is there an easy way to toggle this with a 'public/private' option. Just having trouble figuring out how to model in the database. Can create new projects - that's great - but it seems that all new projects must be associated with invited project users. How to have the option to have some publicly available so that not just project users can view them? Any help would be greatly appreciated. Thanks.
Generally for that, you'd want a
private boolean on the Project.
Then you'd change your query for finding the project. A high level example:
def set_project @project = Project.find(params[:id]) # Private projects require use to verify the user has access. if @project.private? raise ActiveRecord::NotFoundError unless @project.users.include?(current_user) end end
Ideally, you'd use something like Pundit to do the authorization. That way it can be applied always and not be forgotten somewhere.
Thanks Chris. Makes it less complicated than having a separate user has_many projects table if that's even possible given the already-existing join table. I will check out the pundit gem also through Cancancan seems to be working fine so far for me. For the devise invitable links that are sent out in the email notifications here, they all seem to go to root page or sign in page but maybe I'll check out the documentation to see if there's a way to get the url pointing to the project itself after signing in but if you have any advice on that would appreciate it. Your great series saves a lot of time and really appreciate your insights.
Yeah, basically private projects need a ProjectUser association to keep track of who has access. A public one can ignore that since it's open to everyone.
If you're already using CanCan, keep using it. Pundit's just an alternative.
Devise invitable does have a method for doing that, it's in the docs somewhere. 👍
And glad I can be of help!
Chris if you wanted to change button text based on whether someone has been invited to a group (saying already invited for instance) would you go the route of just doing it through js entirely like in the button ainimations or would you do css selectors based on database values that proved invitation? I guess it must br a combination of both? Just seems more complex in this case of invitations going out because it isn't a simple boolean or some other db object that id being referenced by css with id selectors but instead there's an actual invitation outstanding to a particular person . Is this too much database referencing to efficiently and quickly render say an index page of people who have the correct invite or invited buttons? Just wondering how to go about this useful button feature without slowing or messing up an index page. Your insights are always valuable - thank you
I would use the database values. It's not going to slow you down to do that, since you'll already have the database records in memory to display them on the page. You can then do whatever you find easiest to change the buttons.
I would probably just use an if statement to check the different statuses of a user's invitation and then display different buttons accordingly.
Join 20,000+ developers who get early access to new screencasts, articles, guides, updates, and more.