I'm running into this issue working with a form in rails, and was wondering if anybody could take a quick look with it.
My view looks like
= form_for #form_submission do |f|
- if #form_submission.errors.any?
#error_explanation
%h2= "#{pluralize(#form_submission.errors.count, "error")} prohibited this form_submission from being saved:"
%ul
- #form_submission.errors.full_messages.each do |msg|
%li= msg
..and my controller is like so
class FormSubmissionsController < ApplicationController
invisible_captcha only: [:create], on_spam: :handle_spam
def new
#form_submission = FormSubmission.new(form_submission_params)
if #form_submission.save
redirect_to thank_you_path
else
redirect_to root_path
end
end
private
def handle_spam
redirect_to root_path
end
def form_submission_params
params.require(:form_submission).permit(:first_name, :last_name, :organization, :email, :phone)
end
end
Ultimately my problem is that I don't know what params i'm missing. Or even if my value is empty, how would I know, and what could I do to resolve that?
Standard rails approach to forms is your new action is a 'GET' and is used to show the new view for the creation of a resource. The form 'POST's to the create action with the form fields added to the params hash. Your controller methods should be
def new
#form_submission = FormSubmission.new
end
def create
#form_submission = FormSubmission.new(form_submission_params)
if #form_submission.save
redirect_to thank_you_path
else
redirect_to root_path
end
end
Check your routes by running rake routes in the terminal and make sure you have a routes to that point to form_submissions#new and form_submissions#create.
When you click on the submit button you will be able to view the parameters that are being passed in the logs and it should look something like
Parameters: {"utf8"=>"✓", "authenticity_token"=>"someRandomStuff", "form_submission"=>{"first_name"=>"value entered in first_name field", "last_name"=>"value entered in last_name field"}, "commit"=>"Value of submit button"}
Are you really creating a resource called FormSubmission?
I think you're doing it the wrong way.
this is what you should do :
def new
#form_submission = FormSubmission.new
end
def create
#form_submission = FormSubmission.new(form_submission_params)
if #form_submission.save
redirect_to thank_you_path
else
redirect_to root_path
end
end
As said in comments,
"new" action is used to initialize your ressource as empty or with default value.
"create" action is used to save your new ressource
Related
The error: undefined method `model_name' for nil:NilClass (NoMethodError)
I'm receiving this error when trying to render the haml below:
%section#banner
.row
.medium-12.columns
%h2 Add Testimonial
= simple_form_for(#testimonial) do |f|
.row
.large-6.columns
= f.input :text, as: :text,
placeholder: 'Use this space to write a testimonial about the event(s) you participated.'
.row
.large-6.columns
%p.description
= sanitize('Any testimonial along with your name and profile picture might be used for the promotion of codebar (website, prospectus, etc).')
.row
.large-12.columns.text-right
= f.submit 'Submit testimonial', class: 'button'
The controller is the following:
class TestimonialsController < ApplicationController
before_action :authenticate_member!
def get_testimonial
testimonial = Testimonial.where(member_id: testimonial_member_id)
invitations = current_user.workshop_invitations.accepted_or_attended
if invitations.any? and testimonial.blank?
render 'new'
else
render 'show'
end
end
def show
#testimonial = Testimonial.find(testimonial_member_id)
end
def new
#testimonial = Testimonial.new
end
def create
#testimonial = Testimonial.new(testimonial_params)
#testimonial.member_id = current_user
#testimonial.public = false
if #testimonial.save
redirect_to #testimonial
else
render 'new'
end
end
private
def testimonial_params
params.require(:testimonial).permit(:text)
end
def testimonial_member_id
params[current_user]
end
end
May someone help me see why is returning nil? If the variable is the same I'm passing on the new function?
AFAIK simple_form_for(#testimonial) will try to call #testimonial.model_name so that's where the problem most likely originates.
If you go through the get_testimonial controller, you can end up at:
render 'new'
and that will render the HAML in question. But, notice that nothing in get_testimonial initializes #testimonial so get_testimonial will end up trying to simple_form_for(nil).
Changing the bottom of get_testimonial to something more like this:
if invitations.any? && testimonial.blank?
#testimonial = Testimonial.new
render 'new'
else
render 'show'
end
Your show template presumably needs a #testimonial as well so you might want to say #testimonial = testimonial.first before render 'show' too.
Also, I've changed your and operator to && since you're generally better off pretending that and doesn't exist. The low precedence of and and or cause a lot of problems so you're better off sticking to && and ||.
I'm not sure of the logic for testimonials so you might be able to go with something more like:
def get_testimonial
#testimonial = Testimonial.find_by(member_id: testimonial_member_id)
invitations = current_user.workshop_invitations.accepted_or_attended
if invitations.any? && !#testimonial
#testimonial = Testimonial.new
render 'new'
else
render 'show'
end
end
You might want to revisit your testimonial_member_id method as well, this:
def testimonial_member_id
params[current_user]
end
looks odd, maybe it should be params[:id] instead.
I have a Home controller with an index view that acts like a search box that lets the user query a First Table or Second Table through a select box. After a user enters a search term, he will be redirected to the index page of the First or Second model with the search results for that model.
A Search record must be created each time a query is submitted with the search type and search term. However, I don't know how to create a new Search object using simple_form from a different controller, which is the Home controller in this case.
Home Controller
def index
#find = Find.new
Home Index View
= simple_form_for #find, url: finds_path, method: :post do |f|
= f.input :search_type, :collection => [['First', 'First'], ['Second', 'Second']]
= f.input :search_term
= f.button :submit
Finds Controller
def new
#find = Find.new
end
def create
#find = Find.new(find_params)
if params[:search_type] == 'First'
redirect_to first_path
elsif params[:search_type] == 'Second'
redirect_to second_path
else
redirect_to root_path
end
end
private
def find_params
params.permit(:search_term, :search_type, :utf8, :authenticity_token,
:find, :commit, :locale)
# the params seem to come from the Home controller so I added them just to see if they will go through :(
end
It doesn't save. Instead it gives:
Started POST "/en/finds"
Processing by FindsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"..", "find"=>{"search_type"=>"First", "search_term"=>"Something"}, "commit"=>"Create Find", "locale"=>"en"}
Unpermitted parameter: :find
Redirected to http://localhost:3000/en
Unpermitted parameter: :find
Your find_params should be just
def find_params
params.require(:find).permit(:search_type, :search_term)
end
You should access the search_type with params[:find][:search_type]
if params[:find][:search_type] == 'First'
redirect_to first_path
elsif params[:find][:search_type] == 'Second'
redirect_to second_path
else
redirect_to root_path
end
Also, I would suggest renaming the Find model as it conflicts with ActiveRecord#FinderMethods
You need to save, you are just initializing the attributes..
#find = Find.new(find_params)
#find.save!
OR
#find = Find.create!(find_params)
Also, strong parameters should be
def find_params
params.require(:find).permit(:search_term, :search_type)
end
I'm trying to put a new form that creates new "Addicts" in a modal in my home page.
It's a simple form with 2 inputs, that when clicking on New, a modal pops up with that form in my index page.
I can't get it to work because it keeps saying "Couldnt find Addict without an ID".
My Pages Controller
class PagesController < ApplicationController
def home
#addict = Addict.find(params[:id])
#lanzaderas = Lanzadera.all
render 'index'
end
end
My Addict Controller
class AddictsController < ApplicationController
def index
#posts = Addict.all
end
def show
#addict = Addict.find(params[:id])
end
def new
#addict = Addict.new(params[:addict])
end
def create
#addict = Addict.new(params[:addict])
if #addict.save
redirect_to posts_path, :notice => "Your Addict was saved"
else
render "new"
end
end
def edit
end
def update
end
def destroy
end
end
end
My form in my modal
<%= form_for #addict do |f| %>
<%= f.input :name %>
<%= f.input :surname %>
<%= f.input :postal %>
<%= f.submit %>
<% end %>
I know it has something to do with the variable / id not being passed correctly in my Controller, but it's an error I get lots of times and don't know why I happens.
Thanks!
In def home in your PagesController you have this code:
#addict = Addict.find(params[:id])
I suspect, that you don't have the id for 'addict' in your parameters, when you visit your home action.
Do you want to display one particular addict in your 'home' page? If not, you can remove this line.
Update:
Change this in your AddictsController:
def new
#addict = Addict.new
end
In the new action you only "prepare" a new addict object. Using the find method is not possible, since the record hasn't been created yet.
If you're using Rails 4 you also have to permit your parameters (for security reasons; more info here: Railsguides: Strong Parameters)
In your case you have to do 2 things:
First: add this at the bottom of your AddictsController:
private
def addict_params
params.require(:addict).permit(:name, :surname, :postal)
end
Second: use this method in your create action instead of params[:addict]:
def create
#addict = Addict.new(addict_params)
if #addict.save
redirect_to posts_path, :notice => "Your Addict was saved"
else
render "new"
end
end
I have a #miniatures model and a #lines model joined via a #minilines model.
In the #miniature show view I have this link
<%= link_to "Add to product line", new_miniline_path(:miniature_id => #miniature) %>
To a New #miniline form that takes the :miniature_id from a hidden field like so
<%= f.hidden_field :miniature_id, :value => #miniature.id %>
And then you select the desired #line from a dropdown.
This all works. What I can't get to work is for the controller to redirect a user back to the originating #miniature after the create action works.
This is what I have in my new and create actions in the controller
def new
#miniline = Miniline.new(#miniature)
#miniature = Miniature.find(params[:miniature_id])
#lines = Line.all
end
def create
#miniline = Miniline.new(miniline_params)
if #miniline.save
flash[:success] = "Miniature added to product line"
redirect_to miniature_path(#miniature)
else
flash[:success] = "Did not work!!!"
render 'new'
end
end
I've tried various alternatives to miniature_path(#miniature) like plain #miniature and miniature_path(:miniature_id) but to no avail. I suspect my problem is with the passing of the :miniature_id to the #minilines model. Any help very much appreciated as I've been banging my head for an hour or two.
redirect_to miniature_path(#miniline.miniature)
Assuming you have an association setup.
You haven't set #miniature in create which is that that doesn't work
You could also do
redirect_to #miniline.miniature
I have a form for creating a ticket, which needs an id of a project. This works but not when it comes to validation. If validation won't pass 'render :new' is executed and the project_id doesn't come with it.
I have tried 'redirect_to new_ticket_path(:project_id => params[:ticket][:project_id]) which renders the form again, but the error messages won't show up so it seems that I need to use 'render :new'.
How can I pass the project_id back to the form or reach project_id from the form without passing it?
def new
#ticket = Ticket.new
#id = params[:project_id]
#project = Project.find(#id)
end
def create
#ticket = Ticket.new(params[:ticket].merge(:user_id => current_user.id))
if #ticket.save
redirect_to #ticket
else
render :new <--- will render without the project_id
end
end
That will render just the view for 'new', but will not run the controller action. You'd need to set up your variables for the 'new' view in your 'create' action.
From http://guides.rubyonrails.org/layouts_and_rendering.html#using-render
Using render with :action is a frequent source of confusion for Rails
newcomers. The specified action is used to determine which view to
render, but Rails does not run any of the code for that action in the
controller. Any instance variables that you require in the view must
be set up in the current action before calling render.
The easiest way around this is to change 'new':
def new
#ticket = Ticket.new(:project_id => params[:project_id])
end
and change any references to #project in your 'new' form to #ticket.project. At that point, you shouldn't have to add anything to your 'create' action as long as your form includes a hidden field for the ticket's project id.
The easiest way to get this working (and I would do this anyway) is to nest the task resource under projects. That way you will always have project_id available in params.
# config/routes.rb
resources :projects do
resources :tasks
end
The urls will look like projects/123/tasks/new etc. Take a look at rake routes.
Write project id into a hidden field in your form and you will okay. And don't forget to initialize #id in your create action
def new
#ticket = Ticket.new
#id = params[:project_id]
#project = Project.find(#id)
end
def create
#ticket = Ticket.new(params[:ticket].merge(:user_id => current_user.id))
#id = params[:project_id] # but make sure it is under this key in params
if #ticket.save
redirect_to #ticket
else
render :new <--- will render without the project_id
end
end
and in the form add
<%= hidden_field :project_id, '', value: #id %>
Why don't you use:
flash[:alert] = #ticket.errors.inspect
redirect_to new_ticket_path(:project_id => params[:ticket][:project_id])