Rails 3.2 - Nested Resource Passing ID - ruby-on-rails

Okay so my associations are:
Outlet -> has_many :monitorings
Monitoring -> belongs_to :outlet
My Routes:
resources :outlets do
resources :monitorings
end
View:
<%= link_to new_outlet_monitoring_path(#outlet) %>
When I click the link, the logs show that the outlet_id is passed as a parameter to the new page correctly.
But when saving the monitoring record, the outlet_id becomes nil.
Any help?
UPDATE:
# views/monitorings/_form.html.erb
<%= form_for(#monitoring) do |f| %>
<h2>Type of Monitoring</h2>
<fieldset data-role="controlgroup" >
<div class="radio-group">
<%= f.radio_button :mtype, "Full" %><%= f.label :mtype, "Full", value: "Full" %>
<%= f.radio_button :mtype, "Partial" %><%= f.label :mtype, "Partial", value: "Partial" %>
<%= f.radio_button :mtype, "None" %><%= f.label :mtype, "None", value: "None" %>
</div>
</fieldset>
<hr>
<%= f.submit "Next Step" %>
<% end %>
And the controller:
# controllers/monitoring_controller.rb
def new
#monitoring = Monitoring.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #monitoring }
end
end
def create
#monitoring = Monitoring.new(params[:monitoring])
respond_to do |format|
if #monitoring.save
format.html { redirect_to #monitoring, notice: 'Monitoring was successfully created.' }
format.json { render json: #monitoring, status: :created, location: #monitoring }
else
format.html { render action: "new" }
format.json { render json: #monitoring.errors, status: :unprocessable_entity }
end
end
end

This is most likely an issue with the way you are creating the new monitoring record. Can we see your form and your create controller action?

Related

Call create action from different controller

I would like to create a booking from bookings#new and rooms#show. When I try to create it from bookings#new it works, but when try to create it from rooms#show it shows me the error:
1 error prohibited this booking from being saved, room must exist.
Here is the code I'm using:
BookingsController:
def create
if #room
#room = Room.find(params[:room_id])
#booking = #room.bookings.create(booking_params)
if #booking.save
redirect_to room_path(#room)
else
render :new
end
else
#booking = Booking.new(booking_params)
respond_to do |format|
if #booking.save
format.html { redirect_to #booking, notice: 'Booking was successfully created.' }
format.json { render :show, status: :created, location: #booking }
else
format.html { render :new }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
end
views/rooms/show.html.erb
<h2>book this room:</h2>
<%= form_with(model: [ #room, #room.bookings.build ], local: true) do |form| %>
<p>
<%= form.label :traveller %>
<%= form.text_field :traveller %>
</p>
<p>
<%= form.label :startfrom %>
<%= form.datetime_select :startfrom %>
</p>
<p>
<%= form.label :endsat %>
<%= form.datetime_select :endsat %>
</p>
<p>
<%= form.label :bookingref %>
<%= form.text_field :bookingref %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
Your mistake is inside if-else in the controller. You're checking #room before you define it, so it is always nil. It should be:
def create
# use find_by here, otherwise you get RecordNotFound error
#room = Room.find_by(id: params[:room_id])
if #room
# use build, because create saves the instance
#booking = #room.bookings.build(booking_params)
if #booking.save
redirect_to room_path(#room)
else
# I suppose you don't want render bookings/new view here
render 'books/show'
end
else
#booking = Booking.new(booking_params)
respond_to do |format|
# redirect and render logic goes here. BTW, do you really need json response format?
end
end
end
end
Also, define in rooms#show action
#booking = #room.bookings.build
and use the instance in the form to correctly display validation errors
form_with(model: [#room, #booking], local: true) do |form|

undefined local variable or method `user' for #<UsersController:0x0000000570eef0>

I'm new to rails and I'm trying to create a form in two parts. First, you fill in the user form. Then you choose to become a prestataire or a employeur. And by clicking on the respective button, the user form will be saved, and you will be redirected either to the prestataire's form or the employeur's with the recently created user params.
Until now, I didn't manage to send the recently created user params, only saving and redirecting. But then I get this error in the prestataire_controller, since prestataire belong to user. The error is similar when I click on the employeur button:
undefined local variable or method 'user' for #<UsersController:0x0000000570eef0>
format.json { render action: 'show', status: :created, location: #user }
else
format.html { redirect_to new_user_prestataire_path(user_id: user), notice: "Renseignez vos informations de prestataire" } #This is sublined
format.json { render action: 'show', status: :created, location: #user }
end
Here is the code I've written so far:
User Form:
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :civility, 'Titre de civilité: ' %><br>
<%= f.text_field :civility %>
</div>
<div class="field">
<%= f.label :forename, 'Prénom: ' %><br>
<%= f.text_field :forename %>
</div>
<div class="field">
<%= f.label :surname, 'Nom de famille: ' %><br>
<%= f.text_field :surname %>
</div>
<div class="field">
<%= f.label :email, 'Email: ' %><br>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password, 'Mot de passe: ' %><br>
<%= f.password_field :password, size: 40 %>
</div>
<div class="field">
<%= f.label :password_confirmation, 'Confirmation de mot de passe: ' %><br>
<%= f.password_field :password_confirmation, size: 40 %>
</div>
<div class="field">
<%= f.label :phone, 'Numéro de téléphone: ' %><br>
<%= f.text_field :phone %>
</div>
<div class="actions">
<%= f.submit 'Employeur', name: 'employeur' %>
<%= f.submit 'Prestataire', name: 'prestataire' %>
</div>
<% end %>
User controller:
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
if params[:commit] == 'employeur'
format.html { redirect_to new_user_employeur_path, notice: "Renseignez vos informations d'employeur" }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { redirect_to new_user_prestataire_path, notice: "Renseignez vos informations de prestataire" }
format.json { render action: 'show', status: :created, location: #user }
end
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
if params[:commit] == 'employeur'
format.html { redirect_to new_user_employeur_path, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { redirect_to new_user_prestataire_path, notice: "User was successfully updated." }
format.json { head :no_content }
end
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :surname, :forename, :civility, :phone, :employeur)
end
User model:
class User < ActiveRecord::Base
has_one :prestataire
has_one :employeur
validates :email, presence: true, uniqueness: true
validates :password, :forename, :surname, :phone, :civility, presence: true
validates :password, confirmation: true
has_secure_password
end
Routes file:
Workplace::Application.routes.draw do
resources :users do
resources :prestataires
resources :employeurs
end
resources :projets do
resources :feedbacks
resources :offres
end
root 'projets#index'
I was thinking about adding an onclik option on the f.submit and adding an adequate method. But I read somewhere that f.submit was not the best option for this kind of request, but no other suggestion was made. Thanks in advance for your help.
As I said,the error is because it should be #user in this line of your create action
format.html { redirect_to new_user_prestataire_path(user_id: #user), notice: "Renseignez vos informations de prestataire" }
And also,you haven't initialized #user in your update action which may rise in another error in future.Add this line at the beginning of your update action
#user = User.find(params[:id])
You are not defining your #user object on update. Try:
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update(user_params)
if params[:commit] == 'employeur'
format.html { redirect_to new_user_employeur_path, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { redirect_to new_user_prestataire_path, notice: "User was successfully updated." }
format.json { head :no_content }
end
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end

How to make ajax call and show error messages

Two of the action of My registration controller is new and create.
def new
#regist = Regist.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #regist }
end
end
def create
#regist = Regist.new(regist_params)
respond_to do |format|
if #regist.save
format.html { redirect_to #regist, notice: 'Regist was successfully created.' }
format.json { render json: #regist, status: :created, location: #regist }
else
format.html { render action: "new" }
format.json { render json: #regist.errors, status: :unprocessable_entity }
end
end
end
And the new form contain following code.
<%= form_for(#regist) do |f| %>
<% if #regist.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#regist.errors.count, "error") %> prohibited this regist from being saved:</h2>
<ul>
<% #regist.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.collection_select :student_id, Student.all, :id, :name %><br />
</div>
<div class="field">
<%= f.collection_select :semester_id, Semester.all, :id, :name %><br />
</div>
<div class="field">
<% for subject in Subject.find(:all) %>
<%= check_box_tag "regist[subject_ids][]", subject.id %>
<%= subject.name %><br>
<% end %>
</div>
<div class="field">
<%= f.label :date_of_birth %><br />
<%= f.text_field :date_of_birth %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Now, when someone click on submit button I want to make ajax call using remote true if there are validation errors and show the errors without reloading the page. And if there are no validation errors I want the user to be redirected to show page. How can I do this?
First of all you should add a remote: true to your existing form to allow remote action.
TODO this just add on the first line of your form the remote: true,
<%= form_for(#regist, remote: true) do |f| %>
the rest leave it as it is. Then you need to make your controller to respond to remote calls, therefore you need to alter the responds_to block of create action:
respond_to do |format|
if #regist.save
format.html { redirect_to #regist, notice: 'Regist was successfully created.' }
format.json { render json: #regist, status: :created, location: #regist }
format.js { render js: "window.location.href='"+regists_path+"'"}
else
format.html { render action: "new" }
format.json { render json: #regist.errors, status: :unprocessable_entity }
format.js
end
end
The last step you have to do is to add a file to your app/views/regists/ directory
where you should add a create.js.erb file:
<% if #regist.errors.any? %>
$('#new_regist').effect('highlight', { color: '#FF0000'}, 1000); // for highlighting
// or add here whatever jquery response you want to have to your views.
<% end %>
You will get your validation errors displayed like before above the form.
You have to add the redirect to your controller to the desirable action of your choice. I have added for you a window.location.href as a response to the regists_path.

ActiveRecord::RecordNotFound

I am trying to submit a form and getting this error: Couldn't find Event without an ID
Here is the controller:
def create
#event = Event.find(params[:event_id])
#event_sponsorship = EventSponsorship.new(params[:event_sponsorship])
#event_sponsorship.sponsor_id = current_user.id
#event_sponsorship.event_id = #event
respond_to do |format|
if #event_sponsorship.save
format.html { redirect_to #event_sponsorship, notice: 'Event sponsorship was successfully created.' }
format.json { render json: #event_sponsorship, status: :created, location: #event_sponsorship }
else
format.html { render action: "new" }
format.json { render json: #event_sponsorship.errors, status: :unprocessable_entity }
end
end
end
Here is the form:
<%= simple_form_for(#event_sponsorship) do |f| %>
<%= f.error_notification %>
<div class="signin">
<%= f.hidden_field :event_id, value: #event %>
<%= f.hidden_field :sponsor_id, value: current_user.id %>
<%= f.button :submit, :class => "btn btn-success btn-block", value: "Yes" %>
</div>
<% end %>
In the create method the event_id should be found from the URL. Where am I going wrong?
Post your error as seen in your server console, you'll see that your param 'event_id' is a sub key of (I guess) 'event_sponsorship'
Try this:
#event = Event.find(params[:event_sponsorship][:event_id])
And it's even possible that you'll need to use this code:
#event = Event.find(params[:event_sponsorship].delete(:event_id))
That would remove the 'event_id' fron your params, and allow EventSponsorship.new to work without error

Rails create form for model with many to many relation

I have two models, Recipe and Tag, with a has_and_belongs_to_many relation. For this relation I have a simple join table, RecipesTags.
Recipe:
has_and_belongs_to_many :tags
Tag:
has_and_belongs_to_many :recipes
Now upon creating a new recipe, the user gets to fill in which category the recipe belongs to in forms of checkboxes, like "Meat", "Fish", and so on. These categories are in fact just tags in the database.
Problem: the recipes doesn't get any tags saved to it.
Recipe new and create controller methods:
def new
#recipe = Recipe.new
#ingredients = Ingredient.all
#tags = Tag.all
respond_to do |format|
format.html # new.html.erb
format.json { render json: #recipe }
end
end
# POST /recipes
# POST /recipes.json
def create
#recipe = Recipe.new(params[:recipe])
if (params[:tags])
#recipe.tags << params[:tags]
end
respond_to do |format|
if #recipe.save
format.html { redirect_to #recipe, notice: 'Recipe was successfully created.' }
format.json { render json: #recipe, status: :created, location: #recipe }
else
format.html { render action: "new" }
format.json { render json: #recipe.errors, status: :unprocessable_entity }
end
end
end
The view:
<%= form_for(#recipe, :html => {:multipart => true}) do |f| %>
<% if #recipe.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#recipe.errors.count, "error") %> prohibited this recipe from being saved:</h2>
# [ fields that get's saved for the recipe and works fine ]
<% #tags.each do |t| %>
<%= f.label t.name %>
<%= f.check_box :tags, t.name %>
<br />
<% end %>
<%= f.submit 'Submit recipe', :class => 'btn btn-primary' %>
<% end %>
At the moment, I get an error message saying:
undefined method `merge' for "Meat":String
"Meat" is the tag name.
So, what am I doing wrong here?
I think the issue is this line #recipe.tags << params[:tags].
The association method you're calling with << takes an object (in this case expecting a tag object), but in this case it seems you might be passing it a string.
For more info this link may be helpful http://guides.rubyonrails.org/association_basics.html#has_and_belongs_to_many-association-reference, in particular where it refers to collection<<(object, …).
In your controller you'll want to do something like #recipe.tags << tag where tag is a specific tag object.
So, try this:
In your controller
params[:tags].each do |k,v|
#recipe.tags << Tag.find(k)
end
In your view
<% #tags.each do |t| %>
<%= f.label t.name %>
<%= f.check_box "tags[#{t.id}]" %>
<br />
<% end %>
Try this:
def create
#recipe = Recipe.new(params[:recipe])
params[:tags].each do |tag|
#recipe.tags << Tag.find_by_name(tag)
end
respond_to do |format|
if #recipe.save
format.html { redirect_to #recipe, notice: 'Recipe was successfully created.' }
format.json { render json: #recipe, status: :created, location: #recipe }
else
format.html { render action: "new" }
format.json { render json: #recipe.errors, status: :unprocessable_entity }
end
end
end
In view:
<% #tags.each do |t| %>
<%= label_tag t.name %>
<%= check_box_tag "tags[#{t.name}]", t.name %>
<br />
<% end %>

Resources