Edit specific object - ruby-on-rails

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).

Related

error - First argument in form cannot contain nil or be empty

to start out preemptively, I've already looked at various similar articles dealing with this, but I still get the error.
I'm starting out on rails and attempting to create a GPA calculator and tracker application for fun (and spent a lot of time searching through documentation); I have a singular controller and view since redirecting to an entire different page for calculating or saving a new GPA every time would look ugly.
Rails will display everything without error up until I add the form, no other erb is written currently, and the form is meant to submit letter grade values from the "f.selection" tag.
The culprit is #cgpa in <%= form_for #cgpa do |f| %>.
My form from main\index view:
<%= form_for #cgpa do |f| %>
<div class="field">
(...)
</div>
<div class="actions">
<%= f.submit 'Calculate' %>
</div>
<% end %>
My controller:
class MainController < ApplicationController
def index
##cgpa = CurrentGpa.all #currently calls a key_to error while form exists, otherwise no error is raised
#pgpa = PastGpa.all
#csem = CurrentSemester.all
#psem = PastSemester.all
end
def new
#cgpa = CurrentGpa.new
end
def create
(...)
end
end
The routes are simply Rails.application.routes.draw { root 'main#index'; resources :main }
If any other information is needed, just let me know to add >.>
When you use: <%= form_for #cgpa do |f| %> this automatically tries to submit the form to the CurrentGpasController create action and for doing so it sends a request to current_gpas_path. So you don't have this path in routes that is why it throwing error. Either you can add routes for CurrentGpa like:
resources :current_gpas
or you can specify a path in the form_for:
<%= form_for #cgpa, url: any_path do |f| %>
So this will submit your form to that url specified.
If you add the current_gpas routes then do create the controller and action to process your input.
And as mentioned in comments do add the #cgpa = CurrentGpa.new this in index action. The above will solve your error you are getting after that.
Hope this helps.

Default path to look for partial

In my app/views/conversations/index.html.erb, I am writing:
<%= render #conversations %>
hoping that it would find a partial named _conversation.html.erb inside the same directory, and use it to render each elements in #conversations. (The usual Rails way)
But I get a missing template error: Missing partial mailboxer/conversations/_conversation.
I am using a Mailboxer gem, and there were no documentations for this. I know I could render a partial explicitly by <%= render partial: 'conversation', locals: { conversations: #conversations } %>.
Yet still, I would like to know why my app is looking for a partial for #conversations in mailboxer/conversations/, not conversations/, and if there is a way to change this behavior.
More information
<% #conversations.each do |conversation| %>
<%= div_for conversation %>
<% end %>
produces HTML:
<div class="mailboxer_conversation" id="mailboxer_conversation_16"> ... </div>
<div class="mailboxer_conversation" id="mailboxer_conversation_17"> ... </div>
....
Perhaps the mailboxer_ in front of conversation has something to do with this situation also?
This happens because, in later versions of Mailboxer, models are namespaced under Mailboxer. (e.g. Mailboxer::Conversation, Mailboxer::Message.)
I commented on the GitHub issue also.
You could try providing the full path to the partial, e.g.
<%= render :partial => "yourfoldername/conversation", collection: #conversations %>

Moving rails from to from _form.html.erb to application.html.erb

I have most of the functionality done for a site. Now I am trying to make it look nice. I have a _form.html.erb that works great.
<%= form_for(#card) do |f| %>
<% if #card.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#card.errors.count, "error") %> prohibited this card from being saved:</h2>
<ul>
<% #card.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :event %><br />
<%= f.text_field :event %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Files
view
- cards
-- new.html.erb
-- index.html.erb
-- show.html.erb
- layouts
-- application.html.erb
- pages
-- index.html.erb
I make a call for the form from new.html.erb and it works sends it to show.html.erb, just as I want. I'm using bootstrap and decided to make use of the nav bar. I have placed the nav bar code into the application.html.erb. It works just fine, well kind of. I want what would normally be a search function to be the add a new card.
When I add the form call it does not work, when I add it directly to the application page it does not work. I'm not sure, I have spent hours on this. I got it to work only on the show.html.erb page, both index pages would error out. I honestly don't remember how I did this though.
I'm trying to learn by doing, but I am stuck and need some help.
Thank you,
Ian
I guess that when you say that its working in your new.html.erb you have a new action inside your cards_controller, and inside this action you have something like: #card = Card.new
Well, if you want to put this form in another view, like in the application.html.erb you need to set first your #card variable, so you can do something like:
# application_controller:
before_filter :new_card
def new_card
#card = Card.new
end
be aware that all the controller that inherits from application controller will set this #card variable
#instance_variable
The underlying problem here is that you're calling a partial - by design, these are meant to give you the ability to call the functionality the file contains anywhere in your application
The problem you have is you're referencing an #instance_variable directly in your partial.
This isn't normally an issue - if you're using partials like you were originally (to modularize views), it should be okay. The problems arise when you try and use the partials in a more generalized way, as you are doing now:
#app/views/controller/_form.html.erb
<%= form_for(#card) do |f| %>
This relies on the #card instance variable being made available, which won't be if you're loading the partial in any other controller than the cards_controller.
--
Fix
The way to fix this is to either populate the #card instance variable in the application controller (as described by edymerchk), or to pass the raw value through the locals hash of the partial call:
This will allow you to use the card local variable in your partial:
#app/views/controller/_form.html.erb
<%= form_for card do |f| %>
-
Alternatively, you could also set the #card instance variable, as recommended in another answer:
#app/controllers/application_controller.rb
Class ApplicationController < ActionController::Base
before_action :set_card
private
def set_card
#card = Card.new
end
end

Rendering Rails partial form in another partial

I have models called project and test. A project has many tests.
In the index.html.erb of tests, I have:
<%= render #tests %>
So I therefore have a file called _test.html.erb, and in it I have:
<%= render "form" %>
I then have a filed called _form.html.erb with:
<%= form_for([#project, #project.tests.build]) do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<% end %>
But I get an exception:
undefined method `tests' for nil:NilClass
So #project is apparently nil. I understand my set up is a bit strange, so I'm not sure how I would refactor this to work?
Instance variables are accessible from any level of rendering.
You can render 100 partials inside each other and you would still have access to those same ivars.
The problem looks like you aren't actually setting #project anywhere.
You probably are looking for "test.project" in your form.
<%= render #tests, project: #project %>
Then
<%= render 'form', project: project %>
The idea is to pass in the #project instance variable as a local variable.
Are both partials in the same view?
You will also have to pass the #project object to the partial and every partial that uses #project.
Example:
<%= render #tests, project: #project %>

How to write generic code the Rails way for superclass object in Rails partial view?

Problem
My app manages ProjElements, which are subclassed into:
Milestone
Task
Decision
... etc
For a given ProjElement's show.html.erb, you can comment on that project element instance (e.g. you can add a comment on Milestone XYZ or Decision ABC). Like this:
// display project element specific stuff
// - e.g. show.html.erb for Milestone has milestone-specific stuff
// - e.g. show.html.erb for Decision has decision-specific stuff
// provide comment functionality
// - e.g. for Milestone's show.html.erb, code looks like
<%= form_for [#milestone, Comment.new] do |f| %>
<% if #milestone.comments.size > 0 %>
...
<% end %>
<% f.submit %>
<% end %>
Proposed approach
I plan to use a partial for the comment code and use it across the various show.html.erb views for different project elements, as per DRY. But ...
How do I write generic code for the partial, the Rails way, so that the partial can deal with different project elements?
You can pass the element's subclass instance through the locals hash. In app/views/milestones/show.html.erb
render :partial => 'shared/comments', :locals => { :element => #milestone }
In app/views/shared/_comments.html.erb
<% form_for [element, Comment.new] do |f| %>

Resources