After a user logs in, I'm trying to collect additional info to update in the data base
this is my controller
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def additional_info
#user = User.find params[:id]
end
def update
if #user.update(user_addinfo)
redirect_to user_path(#user), notice: 'User was successfully updated.'
else
render action: 'additional_info'
end
end
def create
#user = User.new(user_params)
if #user.save
#session[:user_id] = #user.id
#UserMailer.welcome_email(#user).deliver
sign_in #user
redirect_to additional_info_path(#user)
flash[:success] = "Welcome to InYourShoes!"
else
render'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def user_addinfo
params.require(:user).permit(:year)
end
end
the error occurs at the def update function if #user.update(user_addinfo), rails says its undefined.
def user_addinfo is a action method and def additional_info is the actual page
the view for the page:
<div class="row">
<div class="col-xs-12 col-sm-6 col-sm-offset-3">
<%= form_for(#user, :html => {:class => 'form-horizontal'}) do |f| %>
<fieldset>
<p>Do you have experience in Business? If yes, select one of the following:
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Select one <span class="caret"></span></button>
<ul class="dropdown-menu">
<li>Entrepreneurship</li>
<li>Investments</li>
<li>Management</li>
<li class="divider"></li>
<li>All of the Above</li>
</ul>
</div><!-- /btn-group -->
<%= f.text_field :year , :class => "form-control", :placeholder => "Years of experience" %>
</div>
</p>
<div class = "center form-actions">
<%= f.submit "Submit", class: "btn btn-lg btn-primary" %>
</div>
</fieldset>
<% end %>
</div>
</div>
am i saving the #user in the wrong place? I'm still new to the concept of #variablename instance variable... help and explanation is greatly appreciated
It is because you did't initialize the #user in "update" method.
Usually you need to do something like you did in "show" method.
#user = User.find(params[:id])
You current code, #user in "update" method is nil because you didn't assign any value to it. And a "nil" variable don't have the method "update".
You probably shouldn't try to overload your update function to capture the functionality of both edit and update (which you are doing, the other answers overlooked this). But the reason #user is nil upon form submission is probably because of this line:
render action: 'additional_info'
I'm guessing that line isn't doing what you expect. Rather than run the addition_info action and rendering the form, I believe that is simply performing the render. You probably want to redirect_to 'additional_info' and add a route for it if needed. Then you can ensure that the form is submitting the #user object correctly back to the update function.
You have to fetch the user additional information before updating it
def update
#user = User.find(params[:id])
if #user.update_attributes(user_addinfo)
#your redirection
else
#your redirection
end
end
def update
self.additional_info
if #user.update(user_addinfo)
redirect_to user_path(#user), notice: 'User was successfully updated.'
else
render action: 'additional_info'
end
end
#user doesn't exist with update, you'll need to create it first, which you've kind of done already
Related
i'm newbie in Ruby on rails.
I'm doing CRUD for Articles and have a question: how to keep url and data's form when i create or update a article but it invalid validate?
And if they resolved, how to keep _form.html.erb to use for create and edit view.
I tried some solution in stackoverflow but there are no solution resolved all my problems above.
Here is new article view:
https://ibb.co/bdm4Hxj
You see, url change from /articles
https://ibb.co/wQ6Vxpz
inspect, we see action: /articles, method: post
https://ibb.co/LPJzvLr
and routes in rails:
https://ibb.co/rs1T1PY
_form.html.erb for create and edit view:
<%= form_for #article, html: {class: "form-horizontal"}, local: true do |f| %>
<div class="form-group">
<%= f.label :title, "Title", class: "col-md-2 control-label" %>
<div class="col-md-6">
<%= f.text_field :title, class: "form-control" %>
</div>
</div>
<div class="form-group">
<%= f.label :text, "Text", class: "col-md-2 control-label" %>
<div class="col-md-6">
<%= f.text_area :text, class: "form-control"%>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-4">
<a class="btn btn-success" href="<%= articles_path %>">Back</a>
<%= f.submit action_name.capitalize, class: "btn btn-success" %>
</div>
</div>
<% end %>
My ArticlesController:
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def new
#article = Article.new
end
def show
#article = get_by(:id)
end
def create
#article = Article.new(article_params)
if #article.save
flash[:success] = 'Create success!'
redirect_to articles_path
else
flash[:warning] = 'Something went wrong!'
render :new
end
end
def edit
#article = get_by(:id)
end
def update
#article = get_by(:id)
if #article.update(article_params)
flash[:success] = 'Update success!'
redirect_to articles_path
else
flash[:warning] = 'Update failed!'
render :edit
end
end
def destroy
#article = get_by(:id)
if #article.destroy
flash[:success] = 'Delete success!'
redirect_to articles_path
else
flash[:warning] = 'Delete failed!'
render :new
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
def get_by(id)
Article.find(params[id])
end
end
Thank you and sorry because of my bad english!
Your examples look pretty much what comes out of a scaffold, which is not too bad a start when learning how things can work (rails g scaffold article).
The relevant controller and views are then set up to do exactly what you are asking for: The controller holds a local variable (#article) ready for the view (ultimately _form.erb), whether or not the objects data is valid.
I wonder: What exactly happens? When you save with invalid data, the form should show up with the invalid data still in place. If you compare your form with the one that is created by the scaffold, you will notice that some output regarding validation errors is missing in your example. Try to add it, or start from scratch to see how it looks like.
When the data is valid and you still want the controller to show the user the form after hitting save, instead of redirect_to ... just render :edit.
I have a modal on a searches/show page:
<button name="button" type="button">
<a class="nav-link" data-toggle="modal" data-target="#emailFriendModal" href="">Email Results to Friend</span></a>
</button>
On click, the modal correctly brings up this partial (most of the code redacted for brevity):
<div class="modal fade" id="emailFriendModal">
...
<div class="mx-auto text-left column">
<%=form_with id: :friend_email_form, url: friend_emails_create_path do |f|%>
...
<%= recaptcha_tags %>
<div class="actions">
<%= f.submit "Send Email", class: 'btn btn-primary', "onclick":"submit_form();", "data-dismiss":"modal"%>
</div>
<script>
function submit_form() {
document.getElementById('friend_email_form').submit();
}
</script>
<%end%>
</div>
But on submit, the object is not sent to the friend_emails Controller:
class FriendEmailsController < ApplicationController
def new
#friend_email = FriendEmail.new
end
def create
#friend_email = FriendEmail.new(message: params[:message], email: params[:email], email2: params[:email2], path: params[:path])
if #friend_email.save
redirect_back fallback_location: root_path, notice: "Your email has been sent"
else
redirect_back fallback_location: root_path, notice: "Sorry, something went wrong, please try again"
end
end
def friend_email_params
params.require(:friend_email).permit(:message,:email,:email2,:path)
end
end
When the "Email a Friend" button is clicked, the correct partial pops up, but when the form is submitted, a Tour object is created (not a Friend_email object!!). The tour message is displayed, a tour email is sent. On submit the the info is completely bypassing the Friend_emails controller and going straight to the Tour controller.
Routes:
post "friend_emails/create"
post "tours/create"
Rake Routes:
friend_emails_create POST /friend_emails/create(.:format) friend_emails#create
tours_create POST /tours/create(.:format) tours#create
Tours Controller in case its helpful:
class ToursController < ApplicationController
def index
#tours = Tour.all
end
def new
#tour = Tour.new
end
def create
#tour = Tour.new(day: params[:day], time: params[:time], user_id: params[:user_id], listing_id: params[:listing_id], school_id: params[:school_id],
email: params[:email])
if #tour.save
redirect_back fallback_location: root_url, notice: "Your tour request has been sent; we will be in touch soon with confirmation."
else
redirect_back fallback_location: root_url, notice: "#{#tour.errors.full_messages}"
end
end
def destroy
#tour = Tour.find(params[:id])
#tour.destroy
redirect_back fallback_location: root_url, notice: "Your Tour has been Cancelled"
end
def tour_params
params.require(:tour).permit(:tour_req, :user_id, :listing_id, :school_id, :email, :day, :time)
end
end
And Finally, this is an excerpt from the Application Layout which holds the partials.
<%= yield %>
<% unless user_signed_in? %>
<%= render partial: 'devise/registrations/new' %>
<%= render partial: 'devise/sessions/new' %>
<% end %>
<%= render partial: 'friend_emails/new'%>
<%= render partial: 'tours/new'%>
I figured out the problem. I had two modals in the application layout and the code referenced the same javacript submit() function. The fix was to change the name of the submit() function like this:
<div class="actions">
<%= f.submit "Send Email", class: 'btn btn-primary', "onclick":"submit_form2();", "data-dismiss":"modal"%>
</div>
<script>
function submit_form2() {
document.getElementById('friend_email_form').submit();
}
</script>
Now we have two javascript functions, submit_form() and submit_form2() and everything works as it should.
OK, previously I had a problem with a no template error from users#create, now it complete 200 OK however does not redirect at all. Below is my edited users_controller.rb
I have a Signup, Login, Logout rails application with users as a resource. I am trying to save the first user in the database so I can then login but this error is server output when I try to "users#new" and "users#create" the full error is below, then my users_controller.rb and views/users -> new.html.erb
No template found for UsersController#create, rendering head :no_content
Completed 204 No Content in 35ms (ActiveRecord: 0.5ms)
users_controller.rb
def new
#user = User.new
end
def create
#user = User.new(user_params)
if (#user = User.find_by_email(params[:email]))
flash[:success] = "User already exists."
if #user.save
session[:user_id] = user.id
flash[:success] = "New User created."
redirect_to '/layouts/application'
else
render 'new'
end
end
end
new.html.erb
<h1>Sign Up</h1>
<%= form_with(model: #user) do |f| %>
<p> Username:</br> <%= f.text_field :username %> </p>
<p> Email:</br> <%= f.text_field :email %> </p>
<p> Password:</br> <%= f.password_field :password%></p>
<%= f.submit "Signup" %>
<% end %>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<% for message_error in #user.errors.full_messages %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
Do I have to have another html.erb file? And how can I tell what that has to be? Sorry for the obvious question, newb here.
As per your code if the User is not present it will not enter in the if block. Rails end up trying to find create.html as the current action is create.
To avoid this you must redirect it somewhere or render a template which you have done in the next if and else but it's not executing.
The condition is not letting it redirect to anywhere. Try moving the if block out like this.
def create
#user = User.new(user_params)
if User.exists?(email: params[:email]) # I think this should be `user_params[:email]` instead of `params[:email]`
flash[:error] = "User already exists."
redirect_to 'whereever/you/want/to/redirect' and return
end
if #user.save
session[:user_id] = user.id
flash[:success] = "New User created."
redirect_to '/layouts/application'
else
render 'new'
end
end
I have action index:
def index
if params['type'] == 'random'
#objects = Object.order("RANDOM()").limit(1)
else
#objects = Object.all.limit(1)
end
end
and create action:
def create
object = Object.find(params[:object_id])
comment = object.comments.create(params[:comment].permit(:body))
respond_to do |format|
format.html
format.js #ajax
end
if comment.save
redirect_to root_path(params[:object_id]) #doesn't work
else
flash[:error] = comment.errors.full_messages[0]
redirect_to root_path(params[:object_id]) #doesn't work
end
end
I can comment an object in my index page. When I put a comment, I want to redirect to the object that was commented.
With my code, the page is reloaded, but the next object is displayed, and I cannot see the comment. How can I redirect to the same object?
My root_path
<span class="random-icon"><%= link_to icon('random'), "http://localhost:3000/?type=random" %></span>
<div class="inner-container">
<% #objects.each do |object| %>
<h1 class="title"><%= object.title %></h1>
<p class="obj"><%= object.body %></p>
<h3 class="comments-title">Comments:</h3>
<div id="comments">
<% object.comments.each do |comment| %>
<div class="comments"> <%= comment.body %>
<span class="time-to-now"><%= distance_of_time_in_words_to_now(comment.created_at) %> ago</span>
</div>
<% end %>
</div>
<div id="error"><%= flash[:error] %></div>
<%= form_for([object, object.comments.build], remote: true) do |f| %>
<%= f.text_area :body, class: "text-area" %>
<p class="char-limit">255 characters limit</p>
<%= f.submit "Comment", class: 'button' %>
<% end %>
<% end %>
</div>
If params['type'] is true, Object.order("RANDOM()").limit(1) will always br reevaluated and usually return a new object. To ensure you return to the same object, you might want to store it in session and then check first in your index if there is a liked comment in your sessions, if so, #objects = Object.find(session[:comment_object_id])
def index
if session[:comment_object_id]
#objects = Object.find(session[:comment_object_id])
session.delete(:comment_object_id) # delete the session after use
elsif params['type'] == 'random'
#objects = Object.order("RANDOM()").limit(1)
else
#objects = Object.all.limit(1)
end
end
def create
object = Object.find(params[:id])
comment = object.comments.create(params[:comment].permit(:body))
respond_to do |format|
format.html
format.js #ajax
end
if comment.save
session[:comment_object_id] = :object_id # set the session here
redirect_to root_path # should work now
else
flash[:error] = comment.errors.full_messages[0]
redirect_to root_path #should work now
end
end
This is pretty easy, and you're very close.
Inside your create method, you've got the object you want to redirect to. So just use it directly inside the if comment.save like:
redirect_to object_path(object)
You can get a list of all these path "helpers" via the command:
rake routes
And in that listing, you should see, by the way, that root_path does not accept any arguments ... for future reference.
I am a begginer in Rails, im following code from a book and i am trying stuff to see if it breaks/works, anyway heres my UserControllers classUserController
class UsersController < ApplicationController
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to #user, :notice => 'Cadastro realizado'
else
render :new
end
end
end
And heres my show.html.erb
<p id="notice"><%=notice%></p>
<h2>Perfil: <%=#user.full_name %></h2>
<ul>
<li>Localização: <%= #user.location %> </li>
<li>Bio: <%= #user.bio %></li>
</ul>
<%= link_to 'Editar Perfil', edit_user_path(#user) %>
<%= link_to 'Mostrar Perfil', show_user_path(#user) %>
My problem is in the last line, when i try to acess this page i get a NomethodError,i am trying to understand why, why can i just change that to #user and the page works?
Try:
<%= link_to 'Mostrar Perfil', user_path(#user) %>
or even just
<%= link_to 'Mostrar Perfil', #user %>
In order to see how to name the routes, open a console and run
rake routes