Can I have both index and create actions in the index view? - ruby-on-rails

Using the perennial example of a Blog webapp (and all resources are currently automatically mapped in routes.rb):
I have a simple index page that lists all my Post titles. I would like to add a form at the bottom of this page to quickly create new Posts.
I'm new to Rails and can't seem to figure this out! Please help!

Try something like:
<% form_for Post.new do |form| %>
(Insert fields here:)
<%= form.label :fieldname %>
<%= form.text_field :fieldname %>
<%= form.submit "Create" %>
<% end %>
Add this to app/views/posts/index.html.erb.

Yes you have both index and create actions in the index view.
display list in a index.html.erb then form to create a new post.
after creating new post redirect to index action only.

Related

Wrong action called when using Partial

I’m trying to use Partial to render a form into Edit and Create view (to handle both actions). The problem is that it works with Create action but the form does not work for editing, it only creates. It seems that the app ignore and use create action by default (the submit button is automatically named “Create Expense” instead of “Update Expense”).
By using this kind of route, I want to edit an Expense (that is linked with a Category).
I did the navigation from Category show view to my Expense edit form view like this.
<% #category.expenses.each do |expense| %>
<tr>
<td><%= expense.name %></td>
<td>
<%= link_to "Edit", edit_category_expense_path(#category, expense) %>
</td>
</tr>
<% end %>
I’m using Partial for rendering my form into Expense edit view.
<h1>Edit Expenses</h1>
<%= render "form", expense: #expense %>
Then my form is simply like this.
<%= form_with model: [ #category, #expense] do |form| %>
<p>
<%= form.label :name %><br>
<%= form.text_field :name %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
My Expense controller
def edit
#expense = Expense.find(params[:id])
#category = #expense.category
end
def new
#expense = #category.expenses.new
end
Finally, i'm rendering the creation form in my Category show view.
<h2>Add Expense:</h2>
<%= render 'expenses/form' %>
But I got undefined method 'model_name' for nil:NilClass when I'm trying to access to my Category show view
Solution based on #Chiperific answer
According to my project structure, I had to put #expense = Expense.new in the show action of Category controller. That's where I displayed the form.
As for the edit form, the answer of #Chiperific explains it perfectly
Thanks
.build instantiates a new record. Rails recognizes that the record is new, not persisted, and automatically does what you are seeing (send the form data to the #new action and use 'Create' for the button language.
In your controller, you need to get the existing record you want to edit:
...
def new
#expense = #category.expenses.new
end
def edit
#expense = Expense.find(params[:id])
end
And adjust your form:
<%= form_with model: [ #category, expense ] do |form| %>
...

Edit specific object

I have an edit view. In this view I got a dropdown and a render partial to a form. Like this:
<ul class="dropdown-menu dropdown-user installations">
<% #installations.each do |i| %>
<li>Installation<%= i.installation_id%></li>
<% end %>
</ul>
<div class="ibox-content form-installations">
<%= render :partial => 'installations/test'%>
<%= render 'form_data' %>
</div>
The view to edit the form:
<%= simple_form_for #installation, class: 'form-horizontal' do |f| %>
<%= f.error_notification %>
...
<%end%>
Controller:
def edit
#installations = current_user.installations
#installation = current_user.installations[0]
end
So in this point I can see in dropdown all installations but only can edit the first "current_user.installations[0]". So my objective is to select the installation in dropdown-menu and edit the selected installation. How I can do this?
The simplest way to do this will be to pass the relevant installation to the dropdown:
#app/controllers/installations_controller.rb
class InstallationsController < ApplicationController
def index
#installations = current_user.installations
end
end
#app/views/installations/index.html.erb
<%= render #installations %>
#app/views/installations/_installation.html.erb
<%= simple_form_for installation do |f| %>
...
<% end %>
I think there are some major issues with the structure of your code - which is why you're seeing these problems.
1. Edit
By definition edit is a member route...
This means that Rails expects a single resource to be loaded through that route (hence why you get url.com/:id/edit as the path).
The reason for this is quite simple -- Rails/Ruby are object orientated. This means that each time you create/read/update/destroy (CRUD), you're doing it to an object.
Objects are invoked by using #installation = Installation.new etc... meaning if you want to edit "all" of your installations, you'll basically need to use one of the collection routes for your Installations resource, sending any fields to the update path:
#app/views/installations/_installation.html.erb
<%= simple_form_for installation, method: :patch do |f| %>
...
<% end %>
This should send the updates to the installations#update path of your app, making it work properly.
--
2. Partials
Partials are just views which can have multiple uses; you should only use "local" variables in them.
There are two ways to invoke local scope variables into partials:
passing them in the locals: {} hash
passing them as in the as: :__ switch
In both instances, you're setting the "local" variables inside the partial to have data that was only available outside of it.
For example, you're calling:
<%= simple_form_for #installation
... inside a partial. This is bad because you're relying on #installation -- you're better using installation and populating it as you invoke the partial (as I have done in the code above).

Pass value from view to controller rails

Background: I have a controller -- Recipes, which generates all the recipes I have in the db and I can click one to see the detail info of the certain recipe. In the certain recipe view, I also pass all the comments this recipe has received. Below the comments info I can just make new comments upon this recipe.
Here is the question: I of course have the recipe id ----- #recipe.id. When I fill all the comment information and click submit button, this form will post to another controller -- Comments. But I just don't know how to pass the recipe id I have in this page to the Comments controller.
Recipe Controller:
def show
#For getting the ingredient info from ingredient set
#ingredientset=IngredientSet.where("recipeid=?",set_recipe.id)
#ingredients = Array.new()
i=0
#ingredientset.each do |set|
#ingredients[i]=Ingredient.find(set.ingredientid)
i+=1
end
Recipe Information View:(I only show the part for making the comment)
<!--for adding a new comment-->
<div id="add_comment">
<%= form_for(#comment) do |f| %>
<% hidden_field .....%>
<!--Here I want to pass the #recipe.id value into the comment controller-->
<!--But I dont know should I use hidden_field or something else-->
<!--I was .net MVC developer, so I only know something like #html.hiddenfor() or #ViewBag.xxx stuff-->
<div class="field">
<%= f.label :comment %><br>
<%= f.text_field :comment %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
</div>
Also I don't know how to even get the value in the Comments controller since I'm totally new in ruby on rails.
Here is the Comments controller:
def create
#comment = Comment.new(params[:comment])
#comment.recipeid = params[:recipeid])
end
Thank you very much!
In your case, it does sound like a hidden_field tag is what you want.
So, in your form, you'd add:
f.hidden_field :recipeid, <value>
Personally, if I use a hidden_field tag, I look for another way to do this, since those tags can easily be modified in the DOM before form submission. I'd look to see if there's a way to do this in your controller itself.

multiple forms for different instances of the same object class on the same page in Rails

I have a page with many posts, and each post has a list of comments. At the end of the list is a form for a user to add a comment. Only one comment can be submitted at a time.
Can I get away with something like:
form for #comment
...
form for #comment
or do I need to specifically make sure each form is for a separate object? ie
form for #comment1
...
for for #comment2
If it's the latter, how can I make the main page's controller create one comment object for every post on the page?
You need something like this on your view
<% #posts.each do |post| %>
...
<%= form_for post.comments.build do |f| %>
<%= f.hidden_field :post_id %>
...
<% end %>
<% end %>
or, if you use nested resources in you routes
<% #posts.each do |post| %>
...
<%= form_for [post, Comment.new] do |f| %>
...
<% end %>
<% end %>
You can use Nested model form for this purpose.

Strange routing in rails render partials

I'm new to rails and thought I had finally figured out some of this routing stuff, but have been going in circles with this bit all day.
I was following a tutorial about building a twitter like service, and I've got the basics working from the tutorial, but with Mongo instead of mySql.
I've got 3 types of pages.
The home page which is showing all the posts ordered by date
The user page which is showing the posts from a specific user
The posts page which is showing posts from a users friends.
So for each page, I've done the following
1) created a method in the corresponding controller to get the correct posts
2) created a _posts.html.erb page with the display parameters, which are slightly different on each page
3) referenced the partial in the index.html.erb page for each view.
The controller entries look like this
def index
#posts = Post.all(:order => 'created_at DESC')
end
or
def posts
#posts = Post.all(:conditions => {'user_id' => params[:id]}, :order => 'created_at DESC')
end
and the partials are
<%= render :partial => #posts %>
In each view is a _posts.html.erb file, and each is slightly different
home/_posts.html.erb looks like this
<%= div_for post do %>
Posted <%= time_ago_in_words(post.created_at) %> ago
Posted By <%= post.user_id %>
<%= post.text %>
<% end %>
while posts/_post.html.erb looks like this
<%= div_for post do %>
Posted By <%= post.user_id %>
<%= post.text %>
<% if post.created_at > 52.hours.since %>
<%= distance_of_time_in_words_to_now(post.created_at) %>
<% else %>
<%= post.created_at.strftime("%c") %>
<% end %>
<% end %>
Now the strange part is that on all the pages index.html.erb, users/show.html.erb, posts/index.html.erb, the partial that is being displayed is the posts/_post.html.erb. The others are being completely ignored.
my understanding was that render :partial would take the #posts and render _posts.html.erb from the current view. But this isn't happening, as only the posts/_post.html.erb is being rendered from all views.
I've looked in the routes.rb file, but don't have anything in there that would cause this problem.
Can anybody tell me why I am not displaying the proper partials?
-----------Edited --------------------------------
The directory structure for views is as follows
views
- home
-_post.html.erb
-index.htlm.erb
- layouts
- posts
-_post.html.erb
-index.html.erb
-posts.html.erb
- sessions
- users
-_post.html.erb
-new.html.erb
-show.html.erb
I hope that helps.
"post", :collection => #posts%>
maybe rails automatically defines path to the partial when you pass only collection
You're passing the collection as the argument that rails is expecting to be the name of the partial. Your call to render should look like this
<%= render partial: "post", collection: #posts %>
This will render app/views/posts/_post.html.erb, passing the local variable post to the partial.
Additionally, (is sometimes handy) there's an iteration object that is made available to this view, partial_name_iteration, that has information about the total size of the #posts collection, and the index of the current object.

Resources