Undefined method 'User message path" in Rails 3 project - ruby-on-rails

I am trying to add a link to my Posts>Index page which lets people send direct message (using Simple Private Messaging) to the creator of the Post.
Currently I have a link to /messages/new to do this, but this is not working - Iget the following error in my app when I try to access /messages/new.
I want to replace the link to /messages/new (in POSTS>INDEX file below) with something better that works. Let me know if you have any thoughts!!
**NoMethodError in Messages#new**
Showing /Users/fkhalid2008/loand/app/views/messages/new.html.erb where line #1 raised:
undefined method `user_messages_path' for #<#<Class:0x12a77f198>:0x12a76dce0>
Extracted source (around line #1):
1: <% form_for #message, :url => user_messages_path(#user) do |f| %>
2: <p>
3: To:<br />
4: <%= f.text_field :to %>
ADDITIONAL INFORMATION: The app itself is like Gumtree.com, where Users come and create Posts (e.g. selling my car), and people respond my sending them Messages (through the Simple Pvt Messages plugin).
Thanks!
Faisal
MESSAGES>NEW VIEW
<% form_for #message, :url => user_messages_path(#user) do |f| %>
<p>
To:<br />
<%= f.text_field :to %>
<%= error_message_on #message, :to %>
</p>
<p>
Subject:<br />
<%= f.text_field :subject %>
<%= error_message_on #message, :subject %>
</p>
<p>
Message<br />
<%= f.text_area :body %>
<%= error_message_on #message, :body %>
</p>
<p>
<%= submit_tag "Send" %>
</p>
<% end %>
MESSAGE MODEL
class Message < ActiveRecord::Base
is_private_message
attr_accessor :to
end
ROUTES.RB
Mysalary::Application.routes.draw do
resources :messages do
collection do
post :delete_selected
end
end
resources :users
resources :profiles
resources :pages
resources :posts
get "pages/home"
get "pages/about"
get "pages/legal"
get "pages/feedback"
root :to => 'posts#new'
end
MESSAGES CONTROLLER
class MessagesController < ApplicationController
before_filter :set_user
def index
if params[:mailbox] == "sent"
#messages = #user.sent_messages
else
#messages = #user.received_messages
end
end
def show
#message = Message.read_message(params[:id], current_user)
end
def new
#message = Message.new
if params[:reply_to]
#reply_to = #user.received_messages.find(params[:reply_to])
unless #reply_to.nil?
#message.to = #reply_to.sender.login
#message.subject = "Re: #{#reply_to.subject}"
#message.body = "\n\n*Original message*\n\n #{#reply_to.body}"
end
end
end
def create
#message = Message.new(params[:message])
#message.sender = #user
#message.recipient = User.find_by_login(params[:message][:to])
if #message.save
flash[:notice] = "Message sent"
redirect_to user_messages_path(#user)
else
render :action => :new
end
end
def delete_selected
if request.post?
if params[:delete]
params[:delete].each { |id|
#message = Message.find(:first, :conditions => ["messages.id = ? AND (sender_id = ? OR recipient_id = ?)", id, #user, #user])
#message.mark_deleted(#user) unless #message.nil?
}
flash[:notice] = "Messages deleted"
end
redirect_to :back
end
end
private
def set_user
#user = User.first
end
end
POSTS>INDEX VIEW
<table class="table table-striped">
<tbody>
<% #posts.each do |post| %>
<tr>
<td>I am a <%= post.title %> getting married in <%= post.job %> in <%= post.location %>, and looking for a <%= post.salary %>. My budget is <%= post.salary %>.</td>
<td> <button class="btn" data-toggle="button" onClick="javascript:location.href = '/messages/new';" />Contact</button></td>
<td><%= time_ago_in_words(post.created_at) %> ago.</td>
<!--/.
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
-->
</tr>
<% end %>
</tbody>
</table>

you routes.rb doesn't define path user_messages_path, it's simple :)
If you want nested restful routes, you need something like
resources :users do
resources :messages
end

Just use
<% form_for #message do |f| %>
<% end %>

Related

How to resolve NoMethodError in ror version 4

When I clicked on "display your data" link it is showing me the following error.
Error:
NoMethodError in Users#show
Showing C:/Site/new/app/views/users/show.html.erb where line #10 raised:
undefined method `email' for #<User::ActiveRecord_Relation:0x2bd81e8>
My code snippets are given below.
views/users/index.html.erb
<h1>Choose your option</h1>
<%= link_to "Enter your data",users_new_path %>
<%= link_to "Display your data",users_show_path %>
views/users/new.html.erb
<h1>Enter your data here</h1>
<%= form_for #user,:url => {:action => 'create'} do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field:name,placeholder:"Enter your name" %><br>
<%= f.email_field:email,placeholder:"Enter your email" %><br>
<%= f.text_field:message,placeholder:"Enter your message"%><br>
<%= f.submit "Submit" %>
<% end %>
views/users/show.html.erb
<h1>Display your data</h1>
<ul>
<li>
<p>
<strong>Name:</strong>
<%= #user.name %>
</p>
<p>
<strong>Email:</strong>
<%= #user.email %>
</p>
<p>
<strong>Message:</strong>
<%= #user.message %>
</p>
</li>
</ul>
<%= link_to "Edit",users_edit_path(:id => t.id) %><%= link_to "Delete",users_delete_path(:id => t.id),data: { confirm: 'Are you sure to delete it ?' } %>
<%= link_to "Back",users_index_path %>
controller/users_controller.rb
class UsersController < ApplicationController
def index
end
def new
#user=User.new
end
def create
#user=User.new(users_params)
if #user.save
flash[:notice]="Your data is saved succesfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="You are entering wrong data"
flash[:color]="invalid"
render :new
end
end
def show
#user=User.all
end
def delete
#user=User.find(params[:id])
#user.delete
end
def edit
#edit=User.find(params[:id])
#user=User.new
end
def update
#user=User.find(params[:id])
if #user.update_attributes(update_params)
flash[:notice]="Your data has updated successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="Your data could not update..check it.."
flash[:color]="invalid"
render :edit
end
end
private
def users_params
params.require(:user).permit(:name, :email, :message,pets_attributes: [:name, :email,:message])
end
def update_params
params.require (:user).permit(:name,:email,:message,pets_attributes: [:name,:email,:message])
end
end
model/user.rb
class User < ActiveRecord::Base
has_many :pets
accepts_nested_attributes_for :pets
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :name, :presence => true,:length => { :minimum => 5 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :message, :presence => true
end
You should fix your show action from:
def show
#user = User.all
end
to:
def show
#user = User.find(params[:id])
end
In show action, you have
#user = User.all
which assigns relation with all users to #user variable. That's why you have this error, because you can't query whole relation for email. You should have:
#user = User.find(params[:id])
User.find(params[:id]) returns single User instance.
def show
#user=User.all
end
This will return array of users instead of user, so in order to call email on it you have to iterate loop over it.
<% user in #users %> <!-- I have change #user to #users in show method -->
<h1>Display your data</h1>
<ul>
<li>
<p>
<strong>Name:</strong>
<%= user.name %>
</p>
<p>
<strong>Email:</strong>
<%= user.email %>
</p>
<p>
<strong>Message:</strong>
<%= user.message %>
</p>
</li>
</ul>
<%= link_to "Edit",users_edit_path(:id => t.id) %><%= link_to "Delete",users_delete_path(:id => t.id),data: { confirm: 'Are you sure to delete it ?' } %>
<%= link_to "Back",users_index_path %>
<% end %>
Or just change show method
#user = User.find(params[:id])
fix your show action.
replace
#user = User.all
with
#user = User.find(params[:id])

Form not loading properly in Rails 3

I am having trouble getting my form to load, not sure why this is happening.
THE PROBLEM: When I try to load the form (/messages/new), I get a blank page, no error messages.
REASON FOR THE PROBLEM: I think the problem is that the link between message and user is not being properly established, that's why the form isn't loading properly, but not sure how to fix it.
BACKGROUND: I currently access the form through POSTS/INDEX file (attached below), but I think this is wrong because there should be a unique link for each user...e.g. if I click on the 'Contact' button for a post created by John, the message should go to John, and so on so forth for other users. I am using the Simple Private Messaging plugin.
Grateful for any feedback!
Thanks,
Faisal
MESSAGES>NEW VIEW
<% form_for #message, :url => messages_path(:user_id => #user) do |f| %>
<p>
To:<br />
<%= f.text_field :to %>
<%= error_message_on #message, :to %>
</p>
<p>
Subject:<br />
<%= f.text_field :subject %>
<%= error_message_on #message, :subject %>
</p>
<p>
Message<br />
<%= f.text_area :body %>
<%= error_message_on #message, :body %>
</p>
<p>
<%= submit_tag "Send" %>
</p>
<% end %>
MESSAGE MODEL
class Message < ActiveRecord::Base
is_private_message
attr_accessor :to
end
ROUTES.RB
Mysalary::Application.routes.draw do
resources :messages do
collection do
post :delete_selected
end
end
resources :users
resources :profiles
resources :pages
resources :posts
get "pages/home"
get "pages/about"
get "pages/legal"
get "pages/feedback"
root :to => 'posts#new'
end
MESSAGES CONTROLLER
class MessagesController < ApplicationController
before_filter :set_user
def index
if params[:mailbox] == "sent"
#messages = #user.sent_messages
else
#messages = #user.received_messages
end
end
def show
#message = Message.read_message(params[:id], current_user)
end
def new
#message = Message.new
if params[:reply_to]
#reply_to = #user.received_messages.find(params[:reply_to])
unless #reply_to.nil?
#message.to = #reply_to.sender.login
#message.subject = "Re: #{#reply_to.subject}"
#message.body = "\n\n*Original message*\n\n #{#reply_to.body}"
end
end
end
def create
#message = Message.new(params[:message])
#message.sender = #user
#message.recipient = User.find_by_login(params[:message][:to])
if #message.save
flash[:notice] = "Message sent"
redirect_to user_messages_path(#user)
else
render :action => :new
end
end
def delete_selected
if request.post?
if params[:delete]
params[:delete].each { |id|
#message = Message.find(:first, :conditions => ["messages.id = ? AND (sender_id = ? OR recipient_id = ?)", id, #user, #user])
#message.mark_deleted(#user) unless #message.nil?
}
flash[:notice] = "Messages deleted"
end
redirect_to :back
end
end
private
def set_user
#user = User.first
end
end
POSTS>INDEX VIEW
<table class="table table-striped">
<tbody>
<% #posts.each do |post| %>
<tr>
<td>I am a <%= post.title %> getting married in <%= post.job %> in <%= post.location %>, and looking for a <%= post.salary %>. My budget is <%= post.salary %>.</td>
<td> <button class="btn" data-toggle="button" onClick="javascript:location.href = '/messages/new';" />Contact</button></td>
<td><%= time_ago_in_words(post.created_at) %> ago.</td>
<!--/.
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
-->
</tr>
<% end %>
</tbody>
</table>
messages/new line 1, try changing the opening ERB tag from a silent to loud tag
s/<%/<%=
sourced from http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html

Problem while inserting a record with Form_tag

I have a newbei Question.i want to insert a record to DB. no error occured but record has been not saved successfuly .my model name is adverb and the name of one field is name.here is my code:
<html>
<body>
<% form_tag new_word_url(#adverb), :method => :post do %>
Name : <%= text_field :adverbs,:name %>
</p>
<p>
<%= submit_tag 'Create' %>
</p>
<% end %>
</body>
</html>
and in my route
match '/words/new'=>'words#new'
and Controller:
class WordsController < ApplicationController
def new
#adverb=Adverb.new
end
def create
#adverb=Adverb.create(params[:adverb])
if #adverb
redirect_to :action => 'index'
else
render :action => 'new'
end
end
def index
#adverb =Adverb.find(:all)
end
def edit
#adverb =Adverb.find(params[:id])
end
end
thank you for your helps
Name : <%= text_field :adverbs,:name %>
should be
Name : <%= text_field :adverb,:name %>
AND
<% form_tag new_word_url(#adverb), :method => :post do %>
should be
<% form_tag adverbs_path, :method => :post do %>
and in your routes
resources :adverbs

Rails 3 RoutingError: No route matches {:controller=>"user_sessions"}

I'll just try to outline this as high level as I can. I am trying to access http://localhost:3000/login
The error is:
No route matches {:controller=>"user_sessions"}
And it's erroring on this line in the new.html.erb file below:
<%= form_for(#user_session) do |f| %>
The route in routes.rb is:
match 'login' => 'user_sessions#new', :as => :login
The user_sessions_controller.rb is:
class UserSessionsController < ApplicationController
def new
#user_session = UserSession.new
end
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
flash[:notice] = "Successfully logged in."
redirect_to root_path
else
render :action => 'new'
end
end
def destroy
#user_session = UserSession.find
#user_session.destroy
flash[:notice] = "Successfully logged out."
redirect_to root_path
end
end
And the actual view for the login page is as follows (new.html.erb):
<h1>Login</h1>
<%= form_for(#user_session) do |f| %>
<% if #user_session.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user_session.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user_session.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :login %><br />
<%= f.text_field :login %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
</p>
<p><%= f.submit "Submit" %></p>
<% end %>
Thank you.
Using form_for(#user_session) alone will try to build out the path using a resource you have defined in your routes.rb. Which you currently don't have (I'm assuming, as you didn't mention it. Please correct if I'm wrong.).
A few ways to go..
Add a resource and limit to the ones you need
resources :user_sessions, :only => [:create, :destroy]
These will use the default routing namings, but you can custom that up as you need.
Match out the routes you need.
match 'login' => 'user_sessions#create', :as => :post_login, :via => :post
View
= form_for(#user_session), :url => post_login_path do |f|
...

ActiveRecord::RecordNotFound -- Couldn't find User without an ID

Please see UPDATES at the bottom of the question...
For reference, this problem evolved out of some fixes I made based on a previous problem I was having here: Associating Two Models in Rails (user and profile)
I'm building an app that has a user model and a profile model.
I want to associate these models such that:
- After the user creates an account, he is automatically sent to the "create profile" page, and the profile he creates is connected to only that particular user.
- Only the user who owns the profile can edit it.
I generated the user model using nifty_generators. When the user hits submit for the account creation, I redirect him to the "new profile" view to create a profile. I did this by editing the redirect path in the user controller. The user controller looks like this:
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
flash[:notice] = "Thank you for signing up! You are now logged in."
redirect_to new_user_profile_path(:user_id => #user)
else
render :action => 'new'
end
end
When I click 'submit' to create a new user, it now sends me to the following url, which seems right: localhost:3000/users/6/profile/new. But it throws the following exception:
NoMethodError in
ProfilesController#new You have a
nil object when you didn't expect it!
The error occurred while evaluating
nil.build
The trace indicates that the problem is in the profiles controller, in the New method. The profiles controller looks like this:
def index
#user = User.find(params[:user_id])
#profile = #user.profile(:order => "created_at DESC")
end
def show
#user = User.find(params[:user_id])
#profile = #user.profile.find(params[:id])
end
def new
#user = User.find(params[:user_id])
#profile = #user.profile.build
end
def edit
#user = User.find(params[:user_id])
#profile = #user.profile.find(params[:id])
end
def create
#user = User.find(params[:user_id])
#profile = #user.profile.build(params[:profile])
if #profile.save
flash[:notice] = 'Profile was successfully created.'
redirect_to(#profile)
else
flash[:notice] = 'Error. Something went wrong.'
render :action => "new"
end
end
Additionally, the app also throws an exception when I try to view the index page of the profiles (there are currently no profiles because I can't get past the user creation step to create one). This is the exception:
ActiveRecord::RecordNotFound in ProfilesController#index
Couldn't find User without an ID
This is what the log is telling me:
Processing ProfilesController#index
[GET] Parameters:
{"action"=>"index",
"controller"=>"profiles"}
ActiveRecord::RecordNotFound (Couldn't
find User without an ID):
app/controllers/profiles_controller.rb:5:in
`index'
To give you the rest of the details on the app, the models have the following associations:
Profile belongs _to :user
User has _one :profile
I have this in the routes.rb file: map.resources :users, :has_one => :profile
In the view for the new profile page that's throwing the first exception listed above, I have this:
<% form_for([#user, #profile]) do |f| %>
<%= f.error_messages %>
....
<% end %>
In the view for the profile index that's throwing the second exception explained above, I have this:
<% #profiles.each do |profile| %>
<div class="post">
<div class="left">
<p>Store: </p>
<p>Category: </p>
</div>
<div class="right">
<p><%=h profile.name %></p>
<p><%=h profile.category %></p>
</div>
<div class="bottom">
<p><%= link_to 'Go to profile', user_profile_path(#user, profile) %></p>
<p><%= link_to 'Edit', edit_user_profile_path(#user, profile) %></p>
<p><%= link_to 'Destroy', user_profile_path(#user, profile), :confirm => 'Are you sure?', :method => :delete %></p>
</div>
I've spent hours trying to track down the problem myself as a learning exercise, but at this point I have no idea how to fix this. Appreciate the help!
UPDATE:
jdl, per your request:
profiles/new.html.erb:
<% form_for([#user, #profile]) do |f| %>
<%= f.error_messages %>
<div class="left">
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>required
</p>
<p>
<%= f.label :category %><br />
<%= f.text_field :category %>required
</p>
<p>
<%= f.label :address1 %><br />
<%= f.text_field :address1 %>
</p>
<p>
<%= f.label :address2 %><br />
<%= f.text_field :address2 %>
</p>
<p>
<%= f.label :city %><br />
<%= f.text_field :city %>
</p>
<p>
<%= f.label :state %><br />
<%= f.text_field :state %>
</p>
<p>
<%= f.label :zip %><br />
<%= f.text_field :zip %>required
</p>
<p>
<%= f.label :phone %><br />
<%= f.text_field :phone %>
</p>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
</p>
</div>
<div class="right">
<p>
<%= f.label :website %><br />
<%= f.text_field :website %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
</div>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
routes.rb:
ActionController::Routing::Routes.draw do |map|
map.signup 'signup', :controller => 'users', :action => 'new'
map.logout 'logout', :controller => 'sessions', :action => 'destroy'
map.login 'login', :controller => 'sessions', :action => 'new'
map.resources :sessions
map.resources :users, :has_one => :profile
map.root :controller => "home"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
PROFILES CONTROLLER (as of 8/20/09, 8pm EST)
class ProfilesController < ApplicationController
def index
#users = User.all(:order => "created_at DESC")
end
def show
#user = User.find(params[:user_id])
end
def new
#user.profile = Profile.new
end
def edit
#user = User.find(params[:user_id])
#profile = #user.profile.find(params[:id])
end
def create
#user = User.find(params[:user_id])
#profile = #user.profile.build(params[:profile])
if #profile.save
flash[:notice] = 'Profile was successfully created.'
redirect_to(#profile)
else
flash[:notice] = 'Error. Something went wrong.'
render :action => "new"
end
end
def update
#profile = Profile.find(params[:id])
if #profile.update_attributes(params[:profile])
flash[:notice] = 'Profile was successfully updated.'
redirect_to(#profile)
else
render :action => "edit"
end
end
def destroy
#profile = Profile.find(params[:id])
#profile.destroy
redirect_to(profiles_url)
end
end
Cody, the index page below is throwing the following exception:
NoMethodError in Profiles#index
Showing app/views/profiles/index.html.erb where line #14 raised:
undefined method `name' for #
<div id="posts">
<% #users.each do |profile| %>
<div class="post">
<div class="left">
<p>Store: </p>
<p>Category: </p>
</div>
<div class="right">
<p><%=h profile.name %></p>
<p><%=h profile.category %></p>
</div>
<div class="bottom">
<p><%= link_to 'Go to profile', user_profile_path(#user, profile) %></p>
<p><%= link_to 'Edit', edit_user_profile_path(#user, profile) %></p>
<p><%= link_to 'Destroy', user_profile_path(#user, profile), :confirm => 'Are you sure?', :method => :delete %></p>
</div>
</div>
The error is telling you that in this line:
#profile = #user.profile.build
#user.profile is nil.
Since you haven't created the profile yet, this makes sense. Instead, go for something like this.
#profile = Profile.new(:user_id => #user.id)
Re: The index page throwing an exception.
You are defining #users in your controller, and then referencing #user in your path helpers. Also, iterating over #users should give you User objects, not Profile objects.
It looks like you're trying to use the Profile#index action to show a list of users. That's kind-of OK, in a not-quite-pure-REST way. However, I would expect to see something more like this.
<% #users.each do |user| -%>
<% unless user.profile.blank? -%>
<%= h user.profile.name %>
<%= h user.profile.category %>
<%= link_to 'Go to profile', user_profile_path(user, user.profile) %>
<% end -%>
<% end -%>
hmm.. I thought when User has many profiles, you can then use:
#user.profiles.build
#user.profiles.create
when User has one profile, you have to use:
#user.build_profile
#user.create_profile
Can't be sure, check API
#jdl was correct in that there is no #user.profile object in ProfilesController#new so calling #user.profile.build would throw a nil exception.
You can fix this by instantiating a new Profile object by
#user.profile = Profile.new
Later if #user gets saved then it will trigger a #user.profile and the foreign keys will be set appropriately.
Also in your ProfilesController, the #index and #show actions are kind of weird. Conventionally, the #index action returns a "list of objects" and #show is to display just one object, a specific one given an ID. However, your #index returns a very specific object because it does a User.find with a specific ID. Furthermore, since a user only has one Profile object it doesnt make sense to also load up its Profile object with an ORDER BY. There should only be one so no order is necessary. On top of that, its debatable whether you need to explicitly load the profile object as you can just access it via #user.profile and ActiveRecord will load it on demand. So your new #index looks something like
def index
#users = User.paginate(:all, :order = "created_at desc", :page => 1, :per_page => 10)
end
This assumes you have the WillPaginate plugin, but the gist is that you are loading a LIST of objects, not just one. In your view, if you are iterating over #users and call .profile on an element of that list then ActiveRecord will load the associated Profile on the fly.
Pretty same thing for #show - no need to explicitly load the profile.
def show
#user = User.find(params[:user_id])
end
Do one thing
In ProfileController provide session[:user_id] not params[:user_id]
def show <br>
#user = User.find(session[:user_id])<br>
#profile = #user.profile <br>
end <br>
I hope it works!

Resources