Access to a param in another controller sended by render :template - ruby-on-rails

So im sending a param from a view to a view of another controller
<%= render template: 'dishes/new', :id => #restaurant.id %>
and this is my other controller view:
def new
#dish = Dish.new
#id = params[:id]
end
def create
#dish = Dish.new(dish_params)
respond_to do |format|
if #dish.save
format.html { redirect_to #restaurant, notice: 'dish was successfully created.' }
format.json { render action: 'show', status: :created, location: :restaurant }
else
format.html { render action: 'show', location: :restaurant }
format.json { render json: #restaurant.errors, status: :unprocessable_entity }
end
end
end
private
def dish_params
params.require(:dish).permit( :avatar, :name, :description, [:id])
end
and this is my view who calls the form:
#new.html.erb
<h1>Add a new dish</h1>
<%= render 'dishes/dish_form' %>
then here is the form:
<%= form_for #dish, :url => { :controller => "dishes", action_name => "create" } do |f| %>
<div class="field">
<%= f.label :dish_name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.label :image %>
<%= f.file_field :avatar %>
</div>
<div class="actions">
<%= f.submit 'Add new dish' %>
</div>
<% end %>
but when i try to save it i got this error:

I think your problem comes in when you are expecting your render template: 'dishes/new' to hit your DishesController. That is not what is happening when you are calling the render.
What you're doing is telling rails to load into your current view the template for 'dishes/new', and you're passing 'dishes/new' a variable that it can access when rendering. You aren't sending a param to a controller.
If you want to keep the current set up you have right now, you can make it work with some tweaking.
I'm going to assume that your Dish model belongs to Restaurant, and therefore has restaurant_id as a column. If that is true, then you can add a hidden field to your form for dishes, called restaurant_id, and update your permitted params in your controller to allow the restaurant id to be set on the dish.
Your form would look like this:
<%= form_for #dish, :url => { :controller => "dishes", action_name => "create" } do |f| %>
<%= f.hidden_field :restaurant_id, value: id %>
...
<% end %>
Your permitted params in your controller would look like this:
def dish_params
params.require(:dish).permit(:avatar, :name, :description, :restaurant_id)
end
You can get more information on how the rails rendering is working here

The error is saying that your controller named Restaurants does not have an action named "Show".
One solution would be to add the Action with the name "Show" to the restaurant controller.
The other option may be that you actually created the action you wanted, but you named it something other than "Show".

Related

Using "pluck" -> undefined method for nil:NilClass

I tried using pluck as a shortcut to select one or more attributes without loading a bunch of records just to grab the attributes I want. Which is pretty much 1:1 the intended use (see here: Pluck).
There are 2 tables: "demands" and "parents".
the idea is to create a new entry in the table "demands". The table "demands" contains a column "parent_id" and the demand/parent models are properly associated through belongs_to and has_many.
this is my code using the pluck method:
<%= form.label :parent_id %><br>
<% if can? :optimize, Matching %> <----TEST FOR ADMIN RIGHTS
<%= form.collection_select :parent_id, Parent.all, :id, :fullname %>
<% else %>
<%= #parent.pluck(:name) %> <-----ERROR ERROR ERROR
<%= form.hidden_field :parent_id, value: #parent.pluck(:id) %>
<% end %><br><br>
The corresponding datatable "parents" obviously contains all three of these values, firstname, name and id.
However, this is my error:
undefined method `pluck' for nil:NilClass
error occurs in /app/views/demands/_form.html.erb
update: this is the complete _form.html.erb
<%= form_for Demand.new do |form| %>
<%= form.label :parent_id %><br>
<% if can? :optimize, Matching %>
<%= form.collection_select :parent_id, Parent.all, :id, :fullname %>
<% else %>
<%= #parent.pluck(:name) %>
<%= form.hidden_field :parent_id, value: #parent.pluck(:id) %>
<% end %><br><br>
<%= form.label :demand %><br>
<%= form.number_field :demand %>
<%= form.label :shift_id %><br>
<%= form.collection_select :shift_id, Shift.all, :id, :description %>
<div class="actions">
<%= form.submit 'Post a new job', {:class => "btn btn-primary"} %>
</div>
<% end %>
This is the demand controller action "create"
def new
#demands = Demand.new
if cannot? :optimize, Matching
#parent = Parent.where(parents: {firstname: current_user.firstname, name: current_user.name})
end
end
def create
#demand = Demand.new(demand_params)
respond_to do |format|
if #demand.save
format.html { redirect_to #demand, notice: 'Demand was successfully created.' }
format.json { render :show, status: :created, location: #demand }
else
format.html { render :new }
format.json { render json: #demand.errors, status: :unprocessable_entity }
end
end
end
Thanks in advance for any advice!
Your #parent instance var is only defined in the create action. So, if #demand.save returns false (Invalid object), the exception occurs because #parent is nil

Rails 5: Object's parent ID being lost between the new action and the create action

I'm trying to create a post that will contain it's forum_id that the form resides in. I need both ID to save in the object to achieve that.
I initialize a new #post in the new action using #post = Forum.find(params[:forum_id]).posts.build
Which will spit out unsaved instance of a post containing it the forum_id just as intended.
I then fill out my form here:
<%= form_for #post, :url => {:controller => "posts", :action => "create"} do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_area :description, class: "form-control" %>
</div>
<div class="actions">
<%= f.submit class: "btn btn-primary" %>
</div>
<% end %>
And when I click the submit button and inspect post_params with byebug after the line #post = Post.new(post_params) in the create action, only the :title and :description come through. The forum_id is lost in between actions and I cannot the save #post without it. I have :forum_id whitelisted in my post_params but it's not coming through. I would think that if an instance of post is created in the new action with a forum_id that it should persist into the create action inside post_params but something is wrong here. Here is the relevant information that might help with my issue.
My model's relationships:
# User model
has_many :forums
has_many :posts
# Forum model
belongs_to :user
has_many :posts
# Post model
belongs_to :user
belongs_to :forum
# post_controller
def new
#post = Forum.find(params[:forum_id]).posts.build
end
Post Controller
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
...
# Rest of actions
...
def post_params
params.require(:post).permit(:title, :description, :forum_id, :user_id)
end
end
Form doesn't submit forum_id because it doesn't exist on there
I think you need to add this to that form
<%= f.hidden_field :forum_id %>

How do I display error messages for nested resource validations?

I'm creating a basic blog application and I'm running into issues displaying error messages when a user tries to submit a blank comment. Instead of getting a nice looking error message, an active record error message with the correct validation erorrs. Such as
ActiveRecord::RecordInvalid in CommentsController#create
Validation failed: Name can't be blank, Email can't be blank
In my article/show view I have the following code:
<%= form_for([#article, #article.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #article %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<p><%= f.submit %></p>
<% end %>
My error messages partial looks like this:
<% if target.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(target.errors.count, "error") %> prohibited this record from being saved:</h2>
<ul>
<% target.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I know the answer is simple but I can't figure it out.
Create action in comments controller:
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#article, :notice => 'Comment was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "articles/show" }
format.xml { render :xml => #comment.errors, :status => :unprocessable_entity }
end
end
I had a similar problem. everything seemed to work fine, but I was not getting any errors
The solution i found is to build the comment in article#show instead of the view:
#article = Article.find(params[:id])
#comment = #article.comments.build(params[:comment])
and in your articles#show don't use #article.comments.build but #comment:
<%= form_for([#article, #comment]) do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<p><%= f.submit %></p>
<% end %>
make sure you build the comment in your comment#create as well (you really have no choice though :P)
also, I don't know if it matters (i'm pretty new to ruby), but I think you need to pass f.object instead of #comment.
I think you're saying that you get the big grey-on-white error page, right?
Check the backtrace, but I suspect that this is coming from the create action in the controller, not the view.
If your controller uses save! with the ! at the end, that means that it will raise an error if the record is invalid. save, on the other hand, returns true or false and lets you use simple branch logic to decide how to react.
If my hunch on save! isn't right, though, please post controller code so we can dig deeper :) Thanks!
The solution was to direct the comments created action back to the correct controller/action and target #comment in my error message partial.
Final view
<%= form_for([#article, #article.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #comment %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<p><%= f.submit %></p>
<% end %>
Final create action in comments controller
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#article, :notice => 'Comment was successfully created.') }
format.xml { render :xml => #article, :status => :created, :location => #article }
else
format.html { render :action => "articles/show" }
format.xml { render :xml => #comment.errors, :status => :unprocessable_entity }
end
end

Setting Symbols in Form View - Ruby on Rails

I am having problems trying to set symbol values in a form view. My view has a couple instance variables being used, #task and #team, #team is the one im having issues with. Tasks have a :team value that needs to be set. In this view #team holds a value, but when I hit the "Create" button and make a post, the #team value is lost, and #task contains no team value.
Here is the view I'm dealing with:
Note: the ":team => #task.team" line doesn't work
<% form_for(#task) do |f| %>
<%= f.error_messages %>
<% #task.team = Team.find(#team) %>
<p><%= #task.team.title%></p>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :hours %><br />
<%= f.text_field :hours %>
</p>
<p>
<%= f.label :team %><br />
<% :team => #task.team %>
</p>
<p>
<%= f.submit 'Create'%>
</p>
<% end %>
The Post method that gets called on Create:
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save
format.html { redirect_to(#task, :notice => 'Task was successfully created.') }
format.xml { render :xml => #task, :status => :created, :location => #task }
else
format.html { render :action => "new" }
format.xml { render :xml => #task.errors, :status => :unprocessable_entity }
end
end
end
#Jordinl is right when he mentions that you could use a hidden form field. You can also automatically scope the task to the team in the controller by doing something like
#team = Team.find(params[:team])
and then
#team.tasks << Task.new(params[:task])
You'll need to have a has_many association set up in the team model for tasks
has_many :tasks
for this to work. Each task will also need the team id as well but it sounds like you already have that.
Why don't you set it as a hidden field?
<%= f.hidden_field :team, :value => #task.team %>

How to use a nested form for multiple models in one form?

I'm struggling to come up with the proper way to design a form that will allow me to input data for two different models. The form is for an 'Incident', which has the following relationships:
belongs_to :customer
belongs_to :user
has_one :incident_status
has_many :incident_notes
accepts_nested_attributes_for :incident_notes, :allow_destroy => false
So an incident is assigned to a 'Customer' and a 'User', and the user is able to add 'Notes' to the incident. I'm having trouble with the notes part of the form. Here how the form is being submitted:
{"commit"=>"Create",
"authenticity_token"=>"ECH5Ziv7JAuzs53kt5m/njT9w39UJhfJEs2x0Ms2NA0=",
"customer_id"=>"4",
"incident"=>{"title"=>"Something bad",
"incident_status_id"=>"2",
"user_id"=>"2",
"other_id"=>"AAA01-042310-001",
"incident_note"=>{"note"=>"This is a note"}}}
It appears to be attempting to add the incident_note as a field under 'Incident', rather than creating a new entry in the incident_note table with an incident_id foreign key linking back to the incident.
Here is the 'IncidentNote' model:
belongs_to :incident
belongs_to :user
Here is the form for 'Incident':
<% form_for([#customer,#incident]) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :other_id, "ID" %><br />
<%= f.text_field :capc_id %>
</p>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= label_tag 'user', 'Assign to user?' %>
<%= f.select :user_id, #users.collect {|u| [u.name, u.id]} %>
</p>
<p>
<%= f.label :incident_status, 'Status?' %>
<%= f.select :incident_status_id, #statuses.collect {|s| [s.name, s.id]} %>
</p>
<p>
<% f.fields_for :incident_note do |inote_form| %>
<%= inote_form.label :note, 'Add a Note' %>
<%= inote_form.text_area :note, :cols => 40, :rows => 20 %>
<% end %>
</p>
<p>
<%= f.submit "Create" %>
</p>
<% end %>
And finally, here are the incident_controller entries for New and Create.
New:
def new
#customer = current_user.customer
#incident = Incident.new
#users = #customer.users
#statuses = IncidentStatus.find(:all)
#incident_note = IncidentNote.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #incident }
end
end
Create:
def create
#users = #customer.users
#statuses = IncidentStatus.find(:all)
#incident = Incident.new(params[:incident])
#incident.customer = #customer
#incident_note = #incident.incident_note.build(params[:incident_note])
#incident_note.user = current_user
respond_to do |format|
if #incident.save
flash[:notice] = 'Incident was successfully created.'
format.html { redirect_to(#incident) }
format.xml { render :xml => #incident, :status => :created, :location => #incident }
else
format.html { render :action => "new" }
format.xml { render :xml => #incident.errors, :status => :unprocessable_entity }
end
end
end
I'm not really sure where to look at this point. I'm sure it's just a limitation of my current Rails skill (I don't know much). So if anyone can point me in the right direction I would be very appreciative. Please let me know if more information is needed!
Thanks!
Check api for fields_for method and scroll to one-to-many section.
Your model has many :incident_notes, not one incident_note, that is why it doesn't understand relationship and tries to find a field with this name.
So it should be:
<% f.fields_for :incident_notes do |inote_form| %>
<%= inote_form.label :note, 'Add a Note' %>
<%= inote_form.text_area :note, :cols => 40, :rows => 20 %>
<% end %>
It iterates through all incident_notes assigned to incident and produces fields for each of them.
You also have to build at least one note in you new action, otherwise there will be none:
def new
#incident = Incident.new
#incident.incident_notes.build
# ...
end

Resources