I'm having trouble with nested resources in my Rails4 application. What am I missing here?
I can view the participations/new.html.erb form well but when I submit it's returning "No route matches [POST] "/examinations/1-ales/participations/new" error.
When I'm trying to edit a participation for example this url: localhost:3000/examinations/1-ales/participations/15/edit is returning "ActionController::ParameterMissing in ParticipationsController#edit" and "param not found: participation".
Edit and destroy links in the index.html.erb file causing error:
ActionController::UrlGenerationError in Participations#index
No route matches {:action=>"edit", :controller=>"participations",
:examination_id=>#<Participation id: 12, user_id: 1, examination_id: 1,
payment_status: false, language_preference: "English">,
id=>nil, :format=>nil} missing required keys: [:id]"
routes.rb
resources :examinations do
resources :participations
end
examination.rb
class Examination < ActiveRecord::Base
has_many :participations
has_many :users, :through => :participations
end
participation.rb
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :examination
end
participations_controller.rb
class ParticipationsController < ApplicationController
before_filter :authenticate_user!
before_action :set_participation, only: [:show, :edit, :update, :destroy]
def index
#participations = Participation.all
end
def show
end
def new
#participation = Participation.new
#examination = params[:examination_id]
end
def edit
#examination = params[:examination_id]
#participation = Participation.new(participation_params)
end
def create
#participation = Participation.new(participation_params)
#participation.user = current_user
respond_to do |format|
if #participation.save
redirect_to(#examination)
format.html { redirect_to #participation, notice: 'Sınav Katılımınız Oluşturuldu!' }
else
render 'new'
format.html { render action: 'new' }
end
end
end
def update
respond_to do |format|
if #participation.update(participation_params)
format.html { redirect_to #participation, notice: 'Participation was successfully updated.' }
else
format.html { render action: 'edit' }
end
end
end
def destroy
#participation.destroy
respond_to do |format|
format.html { redirect_to participations_url }
end
end
private
def set_participation
#participation = Participation.find(params[:id])
end
def participation_params
params.require(:participation).permit(:user_id, :examination_id, :payment_status, :language_preference, :exam_center_preference, :disability)
end
end
app/views/participations/new.html.erb
<%= simple_form_for #participation, as: :participation, url: new_examination_participation_path(#examination) do |f| %>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.input :language_preference, collection: ["English", "German"] %>
<%= f.button :submit, "Register to Exam" %>
<% end %>
app/views/participations/edit.html.erb
<%= simple_form_for #participation, as: :participation, url: edit_examination_participation_path(#examination) do |f| %>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.input :language_preference, collection: ["English", "German"] %>
<%= f.button :submit, "Register to Exam" %>
<% end %>
app/views/participations/index.html.erb
** Links, which are causing error in the application.
<%= link_to 'Edit', edit_examination_participation_path(participation), :class => 'btn btn-small' %>
<%= link_to 'Delete', participation, method: :delete, data: { confirm: 'bla bla' }, :class => 'btn btn-small btn-danger' %>
Create a Participation:
In app/views/participations/new.html.erb,
Replace
<%= simple_form_for #participation, as: :participation, url: new_examination_participation_path(#examination) do |f| %>
With
<%= simple_form_for #participation, as: :participation, url: examination_participations_path(#examination, #participation) do |f| %>
examination_participations_path would direct the the request to ParticipationsController #create upon form submission. That is what I think you are trying to achieve => Create a Participation
Update a Participation:
In app/views/participations/edit.html.erb,
Replace
<%= simple_form_for #participation, as: :participation, url: edit_examination_participation_path(#examination) do |f| %>
With
<%= simple_form_for #participation, as: :participation, url: examination_participation_path(#examination, #participation) do |f| %>
examination_participation_path would direct the the request to ParticipationsController #update upon form submission.
List all Participations:
In app/views/participations/index.html.erb,
Replace
<%= link_to 'Edit', edit_examination_participation_path(participation), :class => 'btn btn-small' %>
<%= link_to 'Delete', participation, method: :delete, data: { confirm: 'bla bla' }, :class => 'btn btn-small btn-danger' %>
With
<%= link_to 'Edit', edit_examination_participation_path(#examination, participation), :class => 'btn btn-small' %>
<%= link_to 'Delete', examination_participation_path(#examination, participation), method: :delete, data: { confirm: 'bla bla' }, :class => 'btn btn-small btn-danger' %>
NOTE: I would highly recommend you to read about Nested Resources in Rails guides.
You can always do rake routes and see the list of routes that are available to you.
Related
First of all this is the error
First argument in form cannot contain nil or be empty
What I have is a Thread model and controller and a Answer model and Controller.
And what I am trying to do is edit the answer on the show page of the thread via a zurb Reveal Modal.
and this what my code looks like
Thread Modal
class Thread < ApplicationRecord
belongs_to :user
has_many :answers
extend FriendlyId
friendly_id :subject, use: :slugged
end
Answer Model
class Answer < ApplicationRecord
belongs_to :user
belongs_to :thread
end
Answer Controller
def edit
#thread = Thread.friendly.find(params[:thread_id])
#answer = #thread.answers.find(params[:id])
render :layout => false
end
def update
#thread = Thread.friendly.find(params[:thread_id])
#answer = #thread.answers.find(params[:id])
respond_to do |format|
if #answer.update(params[:answer].permit(:content))
format.html { redirect_to thread_path(#thread) }
format.json { render :show, status: :ok, location: #answer }
else
format.html { redirect_to #thread, alert: "Unable to save your post" }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
Show Thread
<%= render #thread.answers %>
Answer Partial
<% if current_user.present? && current_user.id == answer.user_id %>
<ul class="edit-links pull-right">
<li>
<%= link_to 'Edit', edit_thread_answer_path(answer.thread, answer), :remote => true, class: "edit", "data-open" => "editModal", "data-open-ajax" => edit_thread_answer_path(answer.thread, answer) %>
</li>
<li>
<%= link_to 'Destroy', [answer.thread, answer], method: :delete, data: { confirm: 'Are you sure?' }, class: "destroy" %>
</li>
</ul>
<% end %>
<p>
<%= simple_format answer.content %>
</p>
<div id="editModal" class="reveal" data-reveal>
<%= render :partial => 'answers/edit_form' %>
<button class="close-button" data-close aria-label="Close modal" type="button">
<span aria-hidden="true">×</span>
</button>
</div>
Answer Edit Form Partial
<h1>Edit Answer</h1>
<%= form_for([#thread, #answer]) do |f| %>
<%= f.text_area :content, :rows => "10" %>
<%= f.submit "Update", :class => "button add-thread" %>
<% end %>
I get the error when I try to open a thread#show
its says the error is here
ArgumentError in Threads#show
<%= form_for([#thread, #answer]) do |f| %>
Trace of template inclusion: app/views/answers/_answer.html.erb, app/views/threads/show.html.erb
Any suggestions ? where may the error be ?
My models are
class History < ActiveRecord::Base
belongs_to :projects_lkp
has_many :pictures
accepts_nested_attributes_for :pictures
end
class Picture < ActiveRecord::Base
belongs_to :history
validates_presence_of :pics
end
history/new.html.erb
<%= form_for(:history, :url => {:action => 'create'}) do |d| %>
<%= render(:partial =>"form",:locals => {:d => d}) %>
<% end %>
history/_form.html.erb
<%= d.fields_for :pictures do |dd| %>
<div class="row form-group"></div>
<div><class='col-md-5 form-label'>Photo</div>
<%= dd.file_field :pic, multiple: true, :class => 'col-md-15' %>
</div>
<% end %>
history_controller
def create
#history = History.new(history_params)
#history.projects_lkp_id = params[:projects_lkps_id]
respond_to do |format|
if #history.save
format.html{ redirect_to histories_path(id: #history.id), notice:"History added" }
else
#history = History.where(item: #history.item).all
format.html { render 'index' }
end
end
end
def history_params
params.require(:history).permit(:history,:date,:pic)
end
But when I tried to submit form, it says that unpermitted parameter :pictures
Parameter passing is:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xE8d/mD1pXh/2AIKrZlRoL552iEBVZ7jkzLJB1kNZyE=", "history"=>{"history"=>" jhafjkaalkds", "date"=>"20/10/2014", "pictures"=>{"pic"=>[#<ActionDispatch::Http::UploadedFile:0x0000000143d1f8 #tempfile=#<Tempfile:/tmp/RackMultipart20150910-2753-1ml2hmf>, #original_filename="Firefox_wallpaper.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"history[pictures][pic][]\"; filename=\"Firefox_wallpaper.png\"\r\nContent-Type: image/png\r\n">]}}, "projects_lkps_id"=>"", "commit"=>"Submit"}
Unpermitted parameters: pictures
Here the :pic is the attachment field created by using paperclip gem
Try this:
def history_params
params.require(:history).permit(:history, :date, pictures_attributes: [:pic])
end
One more problem I can see is with your form. It should be:
<%= form_for(:history, :url => {:action => 'create'}, multipart: true) do |d| %>
<%= render(:partial =>"form",:locals => {:d => d}) %>
<%= d.fields_for :pictures do |dd| %>
<div class="row form-group"></div>
<div><class='col-md-5 form-label'>Photo</div>
<%= dd.file_field :pic, multiple: true, :class => 'col-md-15' %>
</div>
<% end %>
<% end %>
Parameters should be in the form:
"history" => { ... , "photos_attributes" => { "0" => { ... } } }
I have found the answer for that :)
history controller
def new
#histories = History.new
#histories.pictures.build
end
history/new
<%= form_for(#histories, :url => {:action => 'create'}, html: {multipart:true}) do |d| %>
<%= render(:partial =>"form",:locals => {:d => d}) %>
<% end %>
it works :)
In my app there is a list of items which you can upvote. I want to make these votes with AJAX calls.
This is the view:
<ul class="list-groups">
<% #questions.each do |question| %>
<li class="list-group-item">
<%= link_to question.description, question_path(question) %>
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), method: :post, html: { class: 'form-inline' }) do |f| %>
<%= f.submit 'Up vote', class: "btn btn-default" %>
<%= f.hidden_field :id, :value => question.id %>
<% end %>
</li>
<% end %>
</ul>
And this the method that does it:
class VoteController < ApplicationController
respond_to :json
def vote
question_id = params[:question][:id]
user_id = current_user.id
vote = Vote.where(["question_id = :q", { q: question_id }]).where(["user_id = :u", { u: user_id }])
respond_to do |format|
if vote.nil?
#vote = Vote.new
#vote.question_id = question_id
#vote.user_id = user_id
#vote.save
format.html { render '/home/index' }
format.json { render :json => { :status => 'ok' } }
else
format.html { render '/home/index' }
format.json { render :json => { :status => 'failed', :msg => 'You already voted' } }
end
end
end
end
If I don't include this format.html { render '/home/index' } I am getting this error:
ActionController::UnknownFormat in VoteController#vote
But I don't want to render the page again, I am just loading the pieces of html that will change after the action with jQuery and ajax.
How can I respond only with the json?
Use respond_with instead of respond_to in your controller action.
respond_with do |format|
respond_to at the top of your controller is designed to work with respond_with in your controller action, whereas respond_to in your controller action ignores the respond_to that you've defined at the top of your controller.
Also make sure you are making a remote call, instead of a normall one if you want your request to go through AJAX.
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), method: :post, remote: true, html: { class: 'form-inline' }) do |f| %>
Note the remote: true part that is added as an argument to the form_for helper.
You need to include remote: true in form_for in order to make the call requests AJAX instead of HTML.
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), remote: true, method: :post, html: { class: 'form-inline' }) do |f| %>
Check out the Working with JavaScript in Rails documentation for more information.
When I'm trying to create a new "participation" in my Rails4 application and it seems like there is something wrong with my parameters. Actually this is not causing any problems in application (or I didn't notice it) but still I would like to fix it. You can see 2 "examination_id" parameters one of them is null and the other one is equal to 1.
REQUEST PARAMETERS:
{"utf8"=>"✓",
"authenticity_token"=>"XZ71eV0zxrnTBilzvEtLlHLwoAb+qKdDfxOHjrAHUPg=",
"participation"=>
{
"language_preference"=>"Türkçe",
"exam_center_preference"=>"1",
"disability"=>"1",
"user_id"=>"1",
"examination_id"=>""
},
"commit"=>"Sınava Başvur",
"examination_id"=>"1"
}
routes.rb:
resources :examinations do
resources :participations do
member do
get :update_profile_information
end
end
end
participation.rb:
class Participation < ActiveRecord::Base
belongs_to :user
belongs_to :examination
before_save :verification_key_generator
end
participations_controller.rb:
class ParticipationsController < ApplicationController
before_filter :authenticate_user!
before_action :set_participation, only: [:show, :edit, :update, :destroy]
before_filter :get_examination
def get_examination
#examination = Examination.find(params[:examination_id])
end
def index
#participations = #examination.participations
end
def show
#participation = #examination.participations.find(params[:id])
end
def new
#participation = Participation.new
end
def create
#participation = #examination.participations.new(participation_params)
#participation.user = current_user
respond_to do |format|
if #participation.save
format.html { redirect_to [#examination, #participation], notice: 'Başvuru işlemi başarıyla tamamlandı!' }
format.json { render action: 'show', status: :created, location: [#examination, #participation] }
else
render 'new'
format.html { render action: 'new' }
format.json { render json: #participation.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #participation.update(participation_params)
format.html { redirect_to [#examination, #participation], notice: 'Başvurunuz Başarıyla Güncellendi!' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: participation.errors, status: :unprocessable_entity }
end
end
end
private
def set_participation
#participation = Participation.find(params[:id])
end
def participation_params
params.require(:participation).permit(:user_id, :examination_id, :payment_status, :language_preference, :exam_center_preference, :disability)
end
end
app/views/participations/_form.html.erb:
<%= simple_form_for([#examination, #participation], html:{class: "well"}) do |f| %>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.input :language_preference, collection: ["Türkçe", "İngilizce", "Rusça"], label: 'Sınav Dili Tercihi' %>
<%= f.input :exam_center_preference, collection:ExamCenter.all, label: 'Sınav Merkezi Seçiniz', label_method: :city %>
<%= f.input :disability, inline_label: 'Yardımcı İstiyorum', label: false %>
<%= f.button :submit, "Sınava Başvur" %>
<% end %>
app/views/participations/new.html.erb:
<%= simple_form_for([#examination, #participation]) do |f| %>
<%= f.error_notification %>
<%= f.input :language_preference, collection: ["Türkçe", "İngilizce", "Rusça"], label: 'Sınav Dili Tercihi' %>
<%= f.input :exam_center_preference, collection:ExamCenter.all, label: 'Sınav Merkezi Seçiniz', label_method: :city %>
<%= f.input :disability, inline_label: 'Yardımcı İstiyorum', label: false %>
<%= f.input :user_id, :as => :hidden, :input_html => { :value => current_user.id } %>
<%= f.input :examination_id, as: :hidden %>
<%= f.button :submit, "Sınava Başvur" %>
<% end %>
sa
When you're using
<%= simple_form_for([#examination, #participation], html:{class: "well"}) do |f| %>
to generate the form, it will set the action to be /examinations/[examination_id]/participations so the routes/action will know the examination_id from the url itself.
So, you don't need to pass examination_id separately as hidden field that you're setting as
<%= f.input :examination_id, as: :hidden %>
Once you remove this hidden field the request parameters will look like:
{"utf8"=>"✓",
"authenticity_token"=>"XZ71eV0zxrnTBilzvEtLlHLwoAb+qKdDfxOHjrAHUPg=",
"participation"=>
{
"language_preference"=>"Türkçe",
"exam_center_preference"=>"1",
"disability"=>"1",
"user_id"=>"1"
},
"commit"=>"Sınava Başvur",
"examination_id"=>"1"
}
I am trying to have a link to delete a certain reservation from the database. This is my solution but it keeps giving Template Error. It shouldn't render the view but it is.
def delete
#current = Reservations.find(params['reservations']['id'])
respond_to do |format|
if current_user
if #current.user_id == current_user.id
#current.destroy
format.html { redirect_to :back }
else
format.html { redirect_to root_path }
end
else
format.html { redirect_to root_path }
end
end
end
My routes file
post "reservations/delete", to: 'reservations#delete', as: 'delete_reservation'
My view that includes the delete link:
<%= form_for item, :url => {:controller => 'reservations', :action => 'delete'}, :method => 'post' do |f| %>
<%= f.hidden_field :id, :value => item.id %>
<%= f.submit "Delete", :class =>'btn btn-danger btn-small' %>
<% end %>