Following Feature From Michael Hartl's Rails Tutorial - ruby-on-rails

I am trying to implement the follower feature from Hartl's RoR tutorial, chapter 12.
I have the feature working in that I can login, go to another user profile, click follow and (after refreshing the page) I see I am now following them. Same with unfollowing.
However, my integration tests fail, the Ajax doesn't work, and I get this error in my Rails server log when I click follow or unfollow:
Rendered users/_follow.html.erb (1.7ms)
Rendered relationships/destroy.js.erb (2.5ms)
Completed 500 Internal Server Error in 17ms
NoMethodError - undefined method `id' for nil:NilClass:
My code matches Hartl's exactly (I think). However, I am using FriendlyID on my User model and Devise, one of which (likely FriendlyID) is causing problems.
I believe this is all the relevant code.
Any ideas would be much appreciated... now on hour 5 or so of this!
controllers/users_controller.rb
def following
#title = "Following"
#user = User.friendly.find(params[:id])
#users = #user.following
render 'show_follow'
end
def followers
#title = "Followers"
#user = User.friendly.find(params[:id])
#users = #user.followers
render 'show_follow'
end
controllers/relationships_controller.rb
def create
user = User.friendly.find(params[:followed_id])
current_user.follow(user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
user = Relationship.find(params[:id]).followed
current_user.unfollow(user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
models/user.rb
# follows a user
def follow(other_user)
active_relationships.create(followed_id: other_user.id)
end
# unfollows a user
def unfollow(other_user)
active_relationships.find_by(followed_id: other_user.id).destroy
end
# returns true if user is following the other user
def following?(other_user)
following.include?(other_user)
end
_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: #user.id),
html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn" %>
<% end %>
_follow.html.erb
<%= form_for(current_user.active_relationships.build(followed_id: #user.id), remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, #user.id %></div>
<%= f.submit "Follow", class: "btn" %>
<% end %>

In your relationships_controller.rb you haven't defined the #user variable, which is why you're receiving the undefined method error. Try this:
def create
#user = User.friendly.find(params[:followed_id])
current_user.follow(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end

Related

First argument in form cannot contain nil or be empty Rails

In my index page I am trying to create a modal that contains a form so that users can create users on the index page. I am using devise to create these users.
However, when I try to create the form for this in the modal, I get this error.
First argument in form cannot contain nil or be empty
<%= form_for #user, html: { multipart: true } do |form| %>
...
<% end %>
Here is my controller:
class UsersController < ApplicationController
before_action :find_account, only: [:index, :new, :create]
def index
if params[:email].present?
#users = User.where(email: params[:email]).first
else
#users = User.all
end
respond_with #users
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to root_url, notice: 'User was sucessfully created' }
else
format.html { render :new }
end
end
end
private
def user_params
params.require(:user).permit(:email, :first_name, :last_name, :password)
end
def find_account
#account ||= Account.find(params[:account_id])
end
end
The user is a nested route because it belongs to an account:
new_account_user GET /accounts/:account_id/users/new(.:format) users#new
Does anybody know why I am getting this error? Since I am creating the #user variable in my controller and finding the account_id in the before_action I am not sure what the problem is.
Update:
If I implement this feature in another form that is working it gives the same error. Possibly something having to do with this not being on the correct action page?
You defined #user but using #material in form and of course #material is nil -> throw the errors.
If the user belongs to account, so the form should be:
<%= form_for [#account, #user], html: { multipart: true } do |form| %>
...
<% end %>
If the user is independent, so the form should be:
<%= form_for #user, html: { multipart: true } do |form| %>
...
<% end %>

Rails remote: true undefined method in view

I have a Rails 5.0.2 app and I've managed to implement a user following system using the acts_as_follower gem. Everything works nicely, however, I'm running into some trouble adding ajax.
I'm getting the following error when clicking 'follow'
NoMethodError at /7/follow
==========================
> undefined method `followed_by?' for nil:NilClass
I have the following
users_controller.rb
def follow
user = User.find(params[:id])
current_user.follow(user)
respond_to do |format|
format.html { redirect_to user}
format.js
end
end
show.html.erb
...
<div id="follow">
<%= render partial: "users/following", locals: {user: #user} %>
</div>
...
_following.html.erb
<% if !#user.followed_by?(current_user) %>
<%= link_to follow_user_path(#user.id), remote: true do %>
<h4><span class="label label-primary">Follow</span></h4>
<% end %>
<% else %>
<%= link_to unfollow_user_path(#user.id) do %>
<h4><span class="label label-primary">Unfollow</span></h4>
<% end %>
<% end %>
I understand that I have no #user in my partial after creating the record and I can't work out how to pass it back in to the partial. Any help would be appreciated.
Silly me.
In the follow method I had this:
def follow
user = User.find(params[:id])
current_user.follow(user)
respond_to do |format|
format.html { redirect_to user}
format.js
end
end
but should have been
def follow
#user = User.find(params[:id])
current_user.follow(#user)
respond_to do |format|
format.html { redirect_to #user}
format.js
end
end
#user rather than user
your problem here is that in your controller you have user, without the "#" user is a variable that exist just in your controller method, and #user is an instance variable that can be accessed on the view.
So if you plan to use this on the view, you need to add "#" to the variable.

Rails 4 - "Create" action in controller when it's a nested route

I have a User model that has_many Photos (another model). In the routes.rb file it's photos is a nested resource of user. So, I have a form_for that uploads to the controller #create action. I'm having trouble saving the photo into the database under the user. How can I do this? It says it saves correctly, because it redirects, but then it doesn't show that it has a photo (I also used the console to check not just my view). What am I doing wrong?
class PhotosController < ApplicationController
def new
#photo = Photo.new(:user_id => params[:user_id])
end
def create
byebug
#photo = Photo.new(params[:user_id])
if #photo.save
flash[:notice] = "Successfully added photo."
redirect_to new_user_photo_path
else
render :action => 'new'
end
end
end
EDIT----------
Adding in the form_for that gets us to the #create action. Hope this helps :) I've been reading more about this, and I'm still not sure what to do to fix.
<%= form_for #photo, :url => user_photos_path(current_user.id, #photo), :html => {:multipart => true} do |f| %>
<div class="form-group">
<%= f.file_field :image %>
</div>
<%= f.submit 'Upload', class: 'btn btn-success' %>
or
<%= link_to 'Cancel', users_path %>
<% end %>
class PhotosController < ApplicationController
def new
#user = User.find(params[:user_id])
#photo = Photo.new(:user_id => params[:user_id])
#photos = #user.photos
end
def create
#photo = User.find(params[:user_id]).photos.new(photo_params)
if #photo.save
flash[:notice] = "Successfully added photo."
redirect_to new_user_photo_path
else
render :action => 'new'
end
end
# GET /photos
def index
redirect_to new_user_photo_path
end
# GET /photos/1
def show
#photo = Photo.find(params[:id])
end
def edit
#photos = Photo.all
#photo = Photo.new
end
def destroy
#photo = User.find(params[:user_id]).photos.find(params[:id])
#photo.destroy
flash[:notice] = "Successfully deleted photo"
redirect_to new_user_photo_path
end
def photo_params
params.require(:photo).permit!
end
end

RoR - Devise: User not logged in when signing up through nested form

I need some help with a RoR application I'm working on. So far it's a pretty simple application and I'm using Devise for authentication.
My application has 2 models, User and Partner. When a Partner creates a new account their 'partner' details are saved to the Partner table and their 'user' details (in this case email and password) to the User table. I did this by creating a form (partners/new) which has a nested form for users.
Partner View new.html.erb
<%= f.inputs do %>
<%= f.input :name %>
<%= f.semantic_fields_for :user do |t| %>
<%= t.input :email %>
<%= t.input :password %>
<%= t.input :password_confirmation %>
<% end %>
<%= f.input :telephone %>
<%= f.input :address %>
<%= f.input :payout_details %>
<%= f.input :preferred_payment %>
<%= f.input :terms_and_conditions, :as => :boolean %>
<% end %>
Partner Model partner.rb
after_initialize :create_user
def create_user
self.user ||= User.new
self.user.roles = "partner"
end
Partner Controller
class PartnersController < ApplicationController
# GET /partners
def index
#partners = Partner.all
end
# GET /partners/1
def show
#partner = Partner.find(params[:id])
end
# GET /partners/new
def new
#partner = Partner.new
end
# GET /partners/1/edit
def edit
#partner = Partner.find(params[:id])
end
# POST /partners
def create
#partner = Partner.new(params[:partner])
sign_in #partner.user
respond_to do |format|
if #partner.save
format.html { redirect_to #partner, notice: 'Partner was successfully created.' }
else
format.html { render action: "new" }
end
end
end
# PUT /partners/1
def update
#partner = Partner.find(params[:id])
respond_to do |format|
if #partner.update_attributes(params[:partner])
format.html { redirect_to #partner, notice: 'Partner was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
# DELETE /partners/1
def destroy
#partner = Partner.find(params[:id])
#partner.destroy
respond_to do |format|
format.html { redirect_to partners_url }
end
end
end
The issue I'm having is although a new partner is created and saved to both the User and Partner tables, they're not automatically logged in like they are when you create a new user through the usual Devise route of users/sign_in.
Could anyone explain where I'm going wrong or what I'm missing?
Thanks.
In your controller, are you doing:
sign_in #partner.user
UPDATE
def create
#partner = Partner.new(params[:partner])
respond_to do |format|
if #partner.save
sign_in #partner.user
format.html { redirect_to #partner, notice: 'Partner was successfully created.' }
else
format.html { render action: "new" }
end
end

User and associated Post

I created an twiiter like app, where friends can post, but i want a include the name of the person who created the post in the list showing all the post.
here is my code
class PostsController < ApplicationController
def index
#posts = Post.all(:order => "created_at DESC")
respond_to do |format|
format.html
end
end
def create
#post = Post.create(:message => params[:message])
respond_to do |format|
if #post.save
format.html { redirect_to posts_path }
format.js
else
flash[:notice] = "Message failed to save."
format.html { redirect_to posts_path }
end
end
end
end
`
Assuming, of course, that the 'user has many posts' association is set, and the user model has a 'username' field, you can do this in your view :
<% #posts.each do |post| %>
<%= post.user.username %>
<% end %>

Resources