.each loop returns []. Form / controller issue - ruby-on-rails

I have RoR 4.2.0beta. (Although it s irrelevant as this is a beginer problem).
My form does not insert in the database the "propuneres" that I am creating trough it. And as a result they do not show in the index page when I get redirected to it. They show up when I create them through the console.
class PropuneresController < ApplicationController
before_action :prop_params
def new
#user = User.find(params[:user_id])
#propunere = #user.propuneres.build
end
def create
#user= User.find(params[:user_id])
#propunere = #user.propuneres.new(params[:prop_params])
#propunere.save
if #propunere.empty?
render 'new'
else
redirect_to user_propuneres_path
end
end
def index
#user = User.find(params[:user_id])
#propunere = #user.propuneres(params[:prop_params])
end
private
def prop_params
params.require(:propunere).permit(:titlu, :body)
end
end
new.html.erb
<h2> Propunere Nouă </h2>
<%= form_for #propunere do |f| %>
<ul>
<% #propunere.errors.full_messages.each do |error| %>
<li><%= error %></li>
<% end %>
</ul>
<p>
<%= f.label :titlu %><br />
<%= f.text_field :titlu %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
index.html.erb
<h2> Propuneri: </h2>
<% #propunere.each do |p| %>
<%= p.titlu %>
<%= p.body %>
<% end %>

Not sure if its relevant, but you have code
#propunere.save
if #propunere.empty?
render 'new'
else
redirect_to user_propuneres_path
end
Object #prorunere will never be empty, since you have
#propunere = #user.propuneres.new, which assigneds user_id to your #propunere object and
render 'new' will never be rendered, therefore you wont see any validation errors and never find out why your record wasnt created
Also since you have that piece of code, and dont see errors, this is what most like broke your code
#user.propuneres.new(params[:prop_params]) - you should use your permitted params, so it'd look like
#propunere = #user.propuneres.new(prop_params)

I've cloned your repo, here's the problem: in new.html.erb you had
&lt%= form_for #propunere, url: new_user_propunere_path(#user, #propunere), html: { method: :get } do |f| %&gt
Both the url and the method are wrong. user_propuneres_path will give you the correct url for the create action and the correct method is :post, not :get. This is why you never reached the create action.
You also need to change from #propunere = #user.propuneres.new(params[:propunere]) to #propunere = #user.propuneres.new(prop_params), otherwise you'll get a ActiveModel::ForbiddenAttributesError exception.
You can see all the routes in the app by running rake routes in the terminal.

I don't think you need the params in your index action:
#propunere = #user.propuneres
and it would be more logical to write it in plural since you have many of them.
Edit:
As Avdept suggested your create action should look like this:
def create
#user = User.find(params[:user_id])
#propunere = #user.propuneres.new(prop_params)
respond_to do |format|
if #propunere.save
format.html { redirect_to user_propuneres_path(#user), notice: 'Your propunere has been saved' }
else
format.html { render :new }
end
end
end

Do you have any validations for the Propunere model? Maybe the model is invalid. You can use
the create! method instead of create for testing, because it will throw an exception if the object cannot be saved. Also try puts #propunere.inspect before persisting it and check that the contents of the object are ok, the output will be shown in the development log.

Related

Rails AJAX link_to not refreshed controller action

In my Rails 5 app, Doctor/Admin have to create a Caregiver with linked Patient (new object CaregiverPatient represents that). During this process, inside the registrants_controller#new, Doctor/Admin search for a Patient (which is done by Ransack gem) and from the result he/she push Add Patient button to add Patient to initialized CaregiverPatient object from caregiver_patient#new and display #patient.full_name inside the form.
In order not to lose already filled form fields, everything must be done asynchronously. I've tried to do so with AJAX, below my code:
registrant_controller.rb
def new
#registrant = Registrant.new
#patient = Registrant.find(session[:patient_id_to_add_caregiver]) if session[:patient_id_to_add_caregiver]
end
registrants/_new_form.html.erb
<%= form_for #registrant do |f| %>
<%= f.fields_for :registration do |registration| %>
<% if #patient %>
<div id="add-patient"></div>
<% else %>
<%= required_text_field_group registration, #registrant, :registrant_id, "Patient Added", {}, { disabled: true } %>
<% end %>
<% end %>
# some other logic (...)
# patient search result
<% #registrants do |registrant| %>
<%= link_to 'Add Patient', new_registrant_link_path(registrant), remote: true %>
<% end %>
Add Patient button triggers caregiver_patients#new action:
#caregiver_patient_controller.rb
class CaregiverPatientsController < ApplicationController
# new_registrant_link_path
def new
session[:patient_id_to_add_caregiver] = params[:registrant_id].to_i
respond_to do |format|
format.html { redirect_to request.referer }
format.js { render action: 'patient_to_caregiver', notice: 'Patient Added' }
end
end
end
AJAX request is made:
#views/caregiver_patients/patient_to_caregiver.js.erb
$("#add-patient").html("<%= escape_javascript(render :partial => 'registrants/add_patient') %>");
views/registrants/_add_patient.html.erb
Patient Added: <%= #patient.full_name %>
But surprisingly gets an error:
ActionView::Template::Error (undefined method `full_name' for nil:NilClass):
1: Patient Added: <%= #patient.full_name %>
Which probably means that registrants_controller#new was not refreshed under the hood somehow. What have I missed?

Allow user to complete form with a delay, error : undefined method `errors' for nil:NilClass

I try to allow user to fill the form with a delay between each user,
The delay is set to 100 between the last user registered in my database and the new one
Here is what I do in my controller :
class EmailsController < ApplicationController
def index
redirect_to root_path
end
def new
#email = Email.new
end
def create
if Time.now - Email.last.created_at < 100
respond_to do |format|
format.html{render :new, notice: "Wait !"}
end
else
respond_to do |format|
#email = Email.create(email_params)
if#email.persisted?
format.html {redirect_to invoice_index_path, notice: 'Email validated '}
else
format.html{render :new}
end
end
end
end
private
def email_params
params.require(:email).permit(:email, :id_user)
end
end
My view :
<div class="container">
<% if flash[:notice].present?%>
<center><p id="notice" class="alert alert-success"><%= flash[:notice] %></p></center>
<%end%>
<center><h1>Nouvelle Connection </h1></center>
<%= form_with model: #email, local: true do |form|%>
<% if #email.errors.any? %>
<div id="error explanation" class="alert alert-danger">
<p>Erreur(s) : </p>
<ul>
<% #email.errors.full_messages.each do |message|%>
<li><%=message%></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= label_tag :email %> :
<%= form.email_field :email, placeholder: "Insérez votre email", class: "form-control" %>
</div>
<div class="form-group">
<%= form.submit class: "btn btn-primary btn-lg btn-block", value: "Se connecter" %>
</div>
<%end%>
</div>
When I fill the form, nothing happen, just the url change from http://localhost:3000/ to http://localhost:3000/emails and when I re-click on Validate, it goes to http://localhost:3000/emails/53 with the error The action 'update' could not be found for EmailsController but I guess I have this error because I don't have any update/edit in my controller.
Do you know how to fix that to allow me a delay between each user ?
Edit : I now have the error undefined method errors for nil:NilClass in my view at the line <% if #email.errors.any? %>. I understand this is because my #email is nil but I tried to integrate this in my view :
<% if #email.nil?%>
<%= Wait for the moment %>
<%end%>
Also tried : <% if #email&.errors&.any? %> why so, I return to the URL : http://localhost:3000/emails
But still have the same error, do you know how to fix it ?
First off, in your view you check for notice.present? and that should be flash[:notice].present?. So then the error will be shown.
Secondly, in your controller you are actually first creating the email, and only then checking if it should be created, and then not even removing it? So the only result is that people will see a notice, but the email would still be created.
So instead do something like:
def create
if Time.now - Email.last.created_at < 100
respond_to do |format|
#email = Email.new(email_params)
format.html do
flash[:notice] = 'Wait! You cannot enter emails so quickly!'
render :new
end
end
else
respond_to do |format|
#email = Email.create(email_params)
if #email.persisted?
format.html {redirect_to invoice_index_path, notice: 'Email validé '}
else
format.html{render :new}
end
end
end
end
Secondly this does seem to mean that any user wanting to enter a new email, will be punished if another user has also entered another email. So in that case you might want to check as follows:
Email.where(created_by_id: current_user.id).last
to only check for Email 's the current user has entered (but maybe that is taking your problem/solution too far?).
Also note there are much better/efficient ways to throttle requests (rate limiting) using apache/nginx (which is probably how it will be deployed), so is this actually a good approach to handle in your ruby on rails code?

Cannot get historical comments to display in a view file

I am trying to add a comments form to a blog post, and have historical comments displayed, too. I created two partials. I can see the comment form in the posts/show view, and I can leave comments, and the comments are added to the database, but those comments are
not displayed.
How can I get these historical comments to be displayed?
Here are my relevant files/excerpts:
app/views/posts/show.html.erb
<%= render partial: '/comments/comment', locals: { comments: #comments} %>
<%= render partial: '/comments/form', locals: { comment: #comment } %>
app/views/comments/_comment.html.erb
<% comments.each do |comment| %>
<%= comment.body + " " + comment.user.name %>
<% end %>
app/views/comments/_form.html.erb
<%= form_for [#post, comment] do |f| %>
<%= f.label :body %>
<%= f.text_area :body %>
<%= f.submit "Save" %>
<% end %>
app/controllers/posts_controller.rb
def show
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
#comments = #post.comments
#comment = Comment.new
end
app/controllers/comments_controller.rb
def create
#post = Post.find(params[:post_id])
#topic = #post.topic
#comment = current_user.comments.new(comment_params)
#comment.post = #post
if #comment.save
redirect_to [#topic, #post], notice: "Comment was saved successfully."
else
flash[:error] = "Error creating comment. Please try again."
render :new
end
end
Thanks.
As far as I can see, if you're sure the comments are being created correctly (and associated with the right post), then there are two main possibilities:
There's something wrong with the way you're rendering the partial. The convention is to leave off the leading /, and I think it might lead to the wrong path (so comments/comment). That said, I think that would raise an error if it didn't find the file, not be silent.
There's some sort of styling or conditional logic hiding the partial. Is there a condition around it that might be false? Is anything display: none for any reason?
The #comments variable could be instantiating incorrectly, but it looks reasonable to me. You can test that out by just adding this line to the top of the show view, and seeing what is printed:
<%= #comments %>
If a bunch of comments are printed, then I'd take that line out, and see what happens when you add <%= comments %> just inside the partial. Narrow down the problem, til you see where it is -- because your above code looks good to me when I look it over.

Repopulating form on failed validation

I have a form for a user to create a question (in additon to user model, there's a question model, with nested answers) on their profile page. It submits from the users profile page /views/users/show.html.erb to the create action of the questions_controller.rb. If it doesn't validate, I think the default for Rails is to render the form(with the invalid information in the form for the user to edit). However, since I'm submitting the form for the question model from the users profile page the prepopulation isn't happening upon failed validation; the user is forced to enter all the information in the form again. Is there a way in this context to get the form on the users show page to fill out with the information that was entered prior to submission?
questions_controller
def create
#question = current_user.questions.build(params[:kestion])
if #question.save
redirect_to current_user, :notice => "Successfully created question."
else
###render :action => 'show'
redirect_to current_user
end
end
Update
I've changed the end of the create method too
Redirect ( : back ), :notice => "something went wrong.try again"
But I still can't get the form to populate, and the validation error messages aren't showing either, only the flash notice.
Update
The show method of the users controller creates the new Question (along with the user)
def show
#user = User.find(params[:id])
#question = Question.new
3.times {#question.answers.build}
end
The /views/users/show.html.erb
<%= form_for #question do |f| %>
<% if #question.errors.any? %>
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question
from being saved: </h2>
<ul>
<% #question.errors.full_messages.each do |msg| %>
<li> <%= msg %></li>
<% end %>
</ul>
<% end %>
<p>
<%= f.label :content, "Question"%>
<%= f.text_area :content, :class => 'span4', :rows => 1 %>
</p>
<p>
<%= f.label :link, "QuoraLink" %>
<%= f.text_field :link, :class => 'span4', :rows => 1 %>
</p>
<%= f.fields_for :answers do |builder| %>
<p>
<%= render 'answer_fields', :f => builder %>
</p>
<% end %>
<p><%= link_to_add_fields "Add Answer", f, :answers %></p>
<p><%= f.submit %></p>
<% end %>
the answer_fields partial rendered from the questions partial
<p class="fields">
<%= f.label :content, "Answer..." %>
<%= f.text_field :content, :class => 'span3', :rows => 1%>
<%= f.label :correctanswer, "Correct" %>
<%= f.check_box :correctanswer, :class => 'span1' %>
<%= link_to_remove_fields "remove answer", f %>
</p>
Currently, in views/users/show.rb you do
#question = Question.new
that creates an empty new question. Then you populate the forms with this empty model.
What you could do instead is:
if session[:question]
#question = #user.questions.new(session[:question])
session[:question] = nil
#question.valid? # run validations to to populate the errors[]
else
#question = Question.new
end
Now all what's left to do is populating session[:question] in your questions_controller before redirecting to :controller=>"users", :action=>"show". Something like:
if #question.save
redirect_to current_user, :notice => "Successfully created question."
else
session[:question] = params[:question]
redirect_to current_user
end
You may need to work on serialization/deserialization additionally for populating/using session[:question]. I didn't try to compile, so am not sure.
All this is needed because when you do redirect_to your processing of the user request ends, the user browser gets a redirect status code from your server and goes for another page, sending you a new request (which lands on the path, and eventually controller/action, to which you redirected to). So, as soon as you return from the request processing, all your variables are lost. For the next request you start from scratch.
The render :action => "show" approach (that was in the original scaffold and that you commented out) worked because you didn't return back to user but simply rendered the template with a specific name using the variables you already had in place (including #question, on which 'save' was called and failed, and thus internally validations were called and populated the errors object).
Actually, that reminded me that you may want to use another approach. Instead of passing parameters through session[] and redirecting to UsersController, you may want to populate all required variables and just render the view from that controller. Like below:
if #question.save
redirect_to current_user, :notice => "Successfully created question."
else
#user = current_user
render "users/show"
end
Firstly, the reason that using redirect_to instead of render doesn't repopulate the form is that when you redirect_to, the controller logic for the action is run, whereas using render ignored the controller logic.
So when you render :action => 'show' (the "default" behaviour), it renders show.html.erb, with #question set like this:
#question = current_user.questions.build(params[:kestion])
When you redirect_to current_user, it renders show.html.erb with #question set using the code in your show action:
#question = Question.new
3.times {#question.answers.build}
This is why you get a new (blank) form, instead of a pre-populated one.
Is it really that important that you use redirect_to? If it is, you'll need to get your show method to do the validation. For example, you could rewrite your show method to something like:
def show
#user = User.find(params[:id])
if params.has_key?(:kestion)
#question = #user.questions.build(params[:kestion])
else
#question = Question.new
3.times {#question.answers.build}
end
end
and then make your form point at that page, with something like:
<%= form_for(#question, url: users_path(#question.user) do |f| %>
...
<% end %>
(depending on how your routes are set up and named). Of course, by that point the whole thing become horribly un-RESTful, a bit of a mess, and definitely not the Rails way of doing things. (The other, worse option would be to redirect back and pass the params through a get query.) In my opinion, you lose a lot for a minor gain, and I'm not sure that I'd really recommend it.

Rails: Access parameters in view after form submission

In my Rails 3.2 project, I have a form to create a new site in new.html.erb in app/views/sites/
<%= form_for(#site) do |site_form| %>
...
<div class="field">
<%= site_form.label :hash_name %><br />
<%= site_form.text_field :hash_name %>
</div>
...
<div class="actions">
<%= site_form.submit %>
</div>
<% end %>
Then the create function in sites_controller.rb
def create
#site = Site.new(params[:site])
respond_to do |format|
if #site.save
format.html { redirect_to #site }
else
format.html { render action: "new" }
end
end
end
Then after the user submits, I want to show the hash_name that the user just submitted, in show.html.erb
You just put in <%= params[:hash_name] %>.
But accessing params[:hash_name] doesn't work. How can I access it?
You're redirecting to a different action - this will reset all the parameters you passed to the create action.
Either pass hash_name as a parameter like the other answer suggests, or just fetch it straight from the #site object.
Just append them to the options:
redirect_to #site, :hash_name => params[:hash_name]

Resources