Update Attributes of a Specific Record - ruby-on-rails

Let's say I have a bunch of cards listed on my wall show action. When you interact with a card (click it for example), I want to update that card's attributes.
I'm currently doing this by getting the card's attributes with Javascript, adding them to a card form and submitting the form remotely.
I have the card's ID, but how do I tell the form which card I want to update?
What should the form and controller update action look like?
This is what I have so far
Form
<%= form_for(#card, remote: true) do |f| %>
<%= f.text_field :list_id %>
<%= f.text_field :order %>
<% end %>
Controller
def update
#card = Card.find(params[:id])
if #card.update_attributes(shared_params)
redirect_to edit_card_path(#card, format: :html)
else
render :edit
end
end

You can use the same new template for edit too. The only requirement here is the object you wanted to edit.
So, first get you edit action ready in controller as
def edit
#card = Card.find(params[:id])
end
edit/new.html.erb
<%= form_for(#card, remote: true) do |f| %>
<%= f.text_field :list_id %>
<%= f.text_field :order %>
<% end %>
In the cards show page, add a link to the edit action as
<%= link_to "Edit", edit_card_path(card.id) %>

Related

How to get Rails form_for to point towards different controller

I have a form for creating new comments. This code exists in a page that is under a different controller (let's say it's app/views/posts/show.html.erb).
<%= form_for Comment.new do |f| %>
<%= f.label :content %>
<%= f.text_field :content %><br/>
<%= f.submit %>
<% end %>
The form works if I have Comment.new like above, but I want to use an instance variable like form_for #comment, similar to the first code snippet in this link: https://api.rubyonrails.org/v5.2.3/classes/ActionView/Helpers/FormHelper.html
In order to do so, I thought I need to define a new function like this and assign an empty comment. I tried putting this code in both the posts_controller and comments_controller.
def new
#comment = Comment.new
end
But when I replace Comment.new with #comment, I get this error: ActionView::Template::Error (First argument in form cannot contain nil or be empty):
This leads me to believe that neither of the new methods are being called. What am I doing wrong here?
My routes.rb looks like this:
Rails.application.routes.draw do
root to: 'posts#show'
resources :messages
end
if you are using show page (app/views/posts/show.html.erb) to display form
add this line in the show action of posts controller
# posts_controller
def show
#comment = Comment.new
end
and if you also want to submit your form other than the comment's create action mention the url in form_for tag
<%= form_for #comment, url: posts_path do |f| %>
<%= f.label :content %>
<%= f.text_field :content %><br/>
<%= f.submit %>
<% end %>

Redirecting to "show" view of a model object when searched by attributes (NOT id)

I have a form where users look for a particular bill by some attributes of that bill, namely the "Congress Number", "Bill Type", and "Bill Number", as in 114-H.R.-67 . I want to "show" the appropriate bill, but to do that I have get the appropriate bill model in a separate action which I've called "find_by_attributes". Inside this action I perform:
#bill = Bill.find_by( params ).first
which correctly acquires the appropriate bill's id.
Now I simply want to redirect to the "show" method of this bill, as in the url
".../bills/[#bill.id]"
As of right now, at the end of my "find_by_attributes" action I do
redirect_to bills_path(#bill)
which correctly loads the show.html.erb with #bill, but does not change the url (the url is still shows the "find_by_attributes" action followed by a long query-string, instead of the clean "/bills/[:bill_id]".
How can I restructure my code to achieve the neat redirect that I desire?
Full code below:
THE FORM
<%= form_tag("bills/find_or_create", :method => :get ) do |f| %>
<%# render 'shared/error_messages', object: f.object %>
<%= fields_for :bill do |ff| %>
<%= ff.label :congress, 'Congress (i.e. 114)' %>
<%= ff.number_field :congress, class: 'form-control' %>
<%= ff.select :bill_type, options_for_select(
[['House of Representatives', 'hr'],
['Senate', 's'],
['House Joint Resolution', 'hjres'],
['Senate Joint Resolution', 'sjres'],
['House Concurrent Resolution', 'hconres'],
['Senate Concurrent Resolution', 'sconres'],
['House Resolution', 'hres'],
['Senate Resolution', 'sres']]
)
%>
<%= ff.label :bill_number, 'Bill number (i.e. 67)' %>
<%= ff.number_field :bill_number, class: 'form-control' %>
<% end %>
<%= submit_tag "Submit", class: "btn btn-primary" %>
<% end %>
THE CONTROLLER ACTIONS
def find_by_attributes
#bill = Bill.where(bill_params).first_or_create(bill_attributes)
redirect_to bills_path(#bill)
end
def show
puts bill_params
if params[:bill]
#bill = Bill.where(bill_params).first_or_create do |bill|
bill.attributes = bill_attributes
end
else
#bill = Bill.find(params[:id])
end
#subjects = Subject.where("bill_id = ?", #bill[:id])
#bill_comments = Comment.where("target = ?", #bill[:id])
end
ROUTES FILE
...
resources :bills do
get :find_by_attributes
end
...
EDIT
I make use of the turbolinks gem in my rails application.
the thing I see here is that you are calling to
redirect_to bills_path(#bill)
that in theory is not the show path, you just need to remove the "s"
redirect_to bill_path(#bill)
and as a side comment, in this line, you don't need the first part, because find_b, finds the first record matching the specified conditions, you can remove that part.
#bill = Bill.find_by( params )

Select_tag login

I would like to have a drop down menu with a list of all the user names in the db. From there, I would like the user to choose his/her name and be able to click login and be taken to their respective page. At this point, a password is not needed. Currently, I have the following:
controller:
def login
#user = User.new
#users = User.all
# #user = User.find_by_id(:id)
# redirect_to user_path(#user)
end
view:
<%= form_for #user, url: '/login', html: {method: 'get'} do |f| %>
<%= f.label "Name" %>
<br/>
<%= select_tag :user, options_for_select(#users) do |users| %>
<%= link_to users.name, users %>
<% end %>
<br/>
<br/>
<%= f.submit 'Login' %>
<% end %>
I cannot seem to link the user to their path and also, i want to show the users name in the drop down menu. Currently, it shows a hexidecimal pointer.
Thank you in advance.
You shouldn't be making a new User object here: you just want to load one out of the database. What you want to do in the controller is just to set current_user to be one of the existing users, right?
Also you've got the form submitting back to the action which loads the form in, which seems weird. I would make it submit to a new action, like "set_current_user" which is a POST action.
in your login template:
<%= form_tag '/set_current_user' do %>
<%= f.label "Name" %>
<br/>
<%= select_tag "user_id", options_for_select(#users.collect{|user| [user.name, user.id] } %>
<br/>
<br/>
<%= submit_tag 'Login' %>
<% end %>
in the controller (you'll need to amend routes.rb to make the '/set_current_user' go to this action) you then need to set something which will keep the user logged in. The traditional way to do this is via session[:user_id], and to have a method current_user which uses this.
def set_current_user
session[:user_id] = params[:user_id]
redirect_to "/" and return
end
Your initial approach is reminiscent of how this sort of thing is normally handled, wherein you do have a form_for, but it's for a UserSession object rather than a User object.

Rails linking form submission to object

In a rails project I have two entities, Users and Institutions, they have a many-to-many relationship.
The views for them are set up to create new users and institutions but I want to have another view for linking the two.
In rails console all I have to do is
myuser.institutions << the_institution_i_just_created
The controller can do some of the work but how do I handle the submissions and the forms? I want to use a selection box so that the input is limited to the Institutions already in existence.
<select id="institution_selection" name="institution_sel">
<% selections = []
Institution.all.each do |institution|
pair = [institution.name, institution.id]
selections.concat([pair])
end
%>
<%= options_for_select(selections) %>
</select>
So the question in summary is how do I map this submission to an object so that in the controller I can do add it to the relation?
The solution was:
Alright, so this is the solution I came up with, I'm sure there is a better way to go about it and I'll continue to look into it but at least I got something close to what I was aiming for
def test
if !session[:user]
redirect_to users_path, notice: "Please login first"
end
if params[:institution]
#user = User.find(session[:user])
#institution = Institution.find(params[:institution][:id])
#user.institutions << #institution
redirect_to #user, notice: "Institution was successfully added "
end
end
and for the view
<%= form_tag("/users/test", :method => "post") do %>
<%= collection_select :institution, :id, Institution.all, :id, :name %>
<%= submit_tag("Search") %>
<% end %>
Use collection_select
<% from for #instancevar do |form| %>
<%= form.collection_select :institution_id, Institution.all, :id, :name %>
# Do other stuff....
<% end %>

Active Admin: Customize only new form

I'm using Active Admin to provide an admin to some models. I need to provide a customized new form for one of them, but leave the edit form as the default provided by Active Admin. Here's what I have. It works in that it is giving me the new form I want, but the edit form is also using the new form, which is not what I want:
ActiveAdmin.register Document do
form :partial => 'form'
end
I've tried this, but it gives an error that 'new' is an undefined method:
ActiveAdmin.register Document do
new do
form :partial => 'form'
end
end
If you just want to hide or show certain fields on the new form (e.g. a field that you generate automatically in the model using before_create), you can do this:
form do |f|
f.inputs "Member Details" do
f.input :first_name
f.input :last_name
f.input :email
if !f.object.new_record?
f.input :password
f.input :password_confirmation
end
end
f.button :Submit
end
This will hide the password fields when you create a new member in the event that you automatically generate passwords the first time the member is created.
I've figured out a way to do it with some logic in the view. Not the best way, to be sure, but it does what I want until I figure out a better way. Here's the logic I'm using:
<% if controller.action_name == 'new' %>
new form
<% else %>
edit form
<% end -%>
I am not sure it can be done directly with form. If you take a look at the code you'll see that only the last call is taken into account. On the other hand, you may try something like:
config.set_page_config :new do
form :partial => 'form'
end
But I would rather ask the developers for this feature.
If someone wants to render different partials for new and edit pages you have to:
#app/admin/document.rb
ActiveAdmin.register Document do
form partial: 'form'
end
#app/views/admin/documents/_form.html.erb
<% if #document.new_record? %>
<%= render partial: "form_new", resource: #document %>
<% else %>
<%= render partial: "form_edit", resource: #document %>
<% end %>
#app/views/admin/documents/_form_new.html.erb
<%= semantic_form_for [:admin, #document], builder: Formtastic::FormBuilder do |f| %>
<%= f.semantic_errors %>
<%= f.inputs do %>
<%= f.input :name %>
<% end %>
<%= f.actions %>
<% end %>
You could create a custom page that acts as the new form, render a partial there which contains arbitrary form code.
So, in your admin directory you make a file new_document.rb containing
ActiveAdmin.register_page "New Document" do
content do
panel "Create a new document" do
render :partial => "admin/documents/custom_form", :locals => {document: Document.new}
end
end
end
You then put your arbitrary formtastic form in admin/documents/custom_form and your arbitrary controller action aka collection_action in admin/documents.
So basically doing normal rails type stuff within the activeadmin framework.

Resources