1

Here's the thing. I have Users and Events and I want to have invitations between them. That is a User can invite another to an Event.

I created an Invitations controller and model. The model looks like this

 user_id: (user being invited), event_id:(event_to_attend), inviter: (sent_the_invite)

I'm building my invitations from the controller by going to /invitations/new and submitting a form but I can't get them to work. They were created before but I made some changes and they don't create, they just say "Invitation has been sent" but no invitation is created in the console or anything.

I know they work because in the console I do

a=User.first
a.invitations.build(event_id: 1, inviter:2)
a.save

And then I can see the invitation and the user_id is the one who created the invitation, a in this case I can see the invitation and can get the user by calling the .invitees method in Event. So the associations work. But I can't create it through the form.

Here's the form

<%= form_for(@invitation) do |f| %>

<% userArray=User.all.select{|u| u.name unless u==current_user }%>
<% names=userArray.map{|u| u.name} %>
<% events=current_user.attended_events.map{|u| u.description} %>

<%= f.label :event %>
<%= f.select :event, events %>

<%= f.label :user %>
<%= f.select :user, names %>

<%= f.submit "Send" %>

<% end %>

I use only name of user and description of event for UX

Here's my invitations controller

class InvitationsController < ApplicationController include ApplicationHelper def new @invitation=Invitation.new end

def create #Not taking into account, duplicate users, and events with the same name by the same user.

#user being invited
@user=User.find_by(name: params[:invitation][:user])


#event being invited to
@event=Event.find_by(description: params[:invitation][:event])


#Inviter is current user, invitee is @user
@user.invitations.build(event_id: @event.id, inviter: current_user.id)

#Event not in user.attended_events
if !(@user.attended_events.where(id: @event.id) || \
    @user.invitations.where("[email protected] AND [email protected]") )

    flash.now[:danger]="User is already going to the event"
    render 'foo'
    #render 'new'

elsif @user.save!
    flash[:success]="Invitation was SENT!"
    redirect_to new_invitation_path
else 
    flash.now[:danger]="Please select both options"
    render 'foobar'
    #render 'new'
end
  end

1 Answer 1

3

Your making it quite a bit harder on yourself than need be.

You can start by using the rails collection helpers to clean up the form:

<%= form_for(@invitation) do |f| %>
  <div class="row">
    <%= f.label :event_id %>
    <%= f.collection_select :event_id, Event.all, :id, :name, prompt: true %>
  </div>

  <div class="row">
    <%= f.label :user_id %>
    <%= f.collection_select :user_id, User.where.not(id: @invitation.inviter.id), :id, :name, prompt: true %>
  </div>

  <%= f.submit %>
<% end %>

This assumes that you have a current_user method and that your Event and User have a name attribute that you want to use for the label (you can use whatever attribute you want). The actual value used is the ID of the associated record.

Note that we use the param key event_id and user_id. Using event would cause an error since the setter expects an actual Event instance and not just an ID.

You would handle this in your controller like so:

class InvitationsController < ActiveRecord::Base
  def new
    @invitation = current_user.invitations.new
  end

  def create
    @invitation = current_user.invitations.new(invitation_params)
    @invitation.save
    respond_with(@invitation)
  end

  private
    def invitation_params
      params.require(:invitation).permit(:event_id, :user_id)
    end
end

This does not handle the issue of creating duplicate invitations yet through. The Rails way of handling this is by adding a uniqueness validation to the model:

class Invitation < ActiveRecord::Base
  belongs_to :user
  belongs_to :invitation
  belongs_to :inviter, class_name: 'User'
  validates_uniqueness_of :user_id, 
    scope: 'invitation_id',
    message: 'is already going to the event'
end

This will cause @invitation.save to fail if the user has already been invited and render the new view again.

Due to the possibility of race conditions you should back the validation with a database index.

# generate with
# $ rails g migration AddUniqueIndexToInvitation
class AddUniqueIndexToInvitation < ActiveRecord::Migration
  def change
    add_index :invitations, [:user_id, :event_id], unique: true
  end
end
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.