How can I have multiple forms to update the same model? - ruby-on-rails

I am new to Rails.
I have a User model. I would like a web page that allows users to change their :name and :email, and another web page that allows them to change their password.
Right now, I have a form to edit :name and :email at
/users/1/edit
The form on the page is
<%= form_for(#user) do |f| %>
My routes.rb has
resources :users
This works. Users can edit their :name and :email just fine. How do I now set up another web page with another form that allows them to change their password?
Thank you.

You can set up any actions you like in your controller. The default CRUD operations are there to cover the basics, but there is no inherent limitation to what you can do.
#controller:
def change_password
render :action => "change_password"
end
#routes:
map.resource :users, :member => {:change_password => :get}
#view:
<%= form_for(#user) do |f| %>
The above would create the route:
/users/1/change_password
In the view you simply have the change password fields => the form basically stays the same, submitting to your existing update action.

Per the comment from Sanjay regarding Toby's answer (and to save anyone the few minutes that I took to figure it out) in Rails 3 you would define the routes with:
#routes:
resources :users do
member do
get 'change_password'
end
end

Related

Rails: Error on form_tag custom action

About a year and a half ago I took an online course in Ruby on Rails using version 3.2. I got through the class and made the application and now I'm going back through the class PDFs and doing it in Rails 4.1.0.
I've got to a section where I'm getting an error and I'm not sure if I'm doing something wrong or if something changed from Rails 3.2 to 4.1.
I've got this form_tag tag:
<%= form_tag :action => 'review', :id => #restaurant do %>
<strong>Poster: </strong><%= text_field "review", "poster" %><br /><br />
<strong>Date: </strong><%= datetime_select "review", "date" %><br /><br />
<strong>Review:</strong><br />
<%= text_area "review", "review", :rows => 5 %><br />
<%= submit_tag "Review" %>
<% end %>
The instructions say to get this to work to put the following code in the restaurants_controller.rb file:
def review
Restaurant.find(params[:id]).reviews.create(params[:review])
redirect_to :action=>"show", :id => params[:id]
end
But when I try and view the page that has the for for it I get this error:
No route matches {:action=>"review", "controller=>"restaurants", :id=>#<Restaurant id: 1, name: "Marco & Luca", created_at: "...", updated_at: "..."
My rake routes shows that show is mapped to the restaurants#show is mapped to the restaurant path.
Is the form_tag piece wrong?
In the instructions from the class we didn't set up anything in routes.rb, I'm guessing that's because of the redirect_to line in the controller file. Is that deprecated now? Is that no longer valid?
Routes file as requested: (in the class exercise we didn't have to edit the routes file).
Rails.application.routes.draw do
# You can have the root of your site routed with "root"
root 'restaurants#index'
resources :restaurants do
collection do
get 'login'
get 'register'
post 'newuser'
post 'validate'
post 'search'
end
end
Thanks!
You do need a route for that. The way it works is:
User fills in a form on some page and sends data to review route
Server processes user's data and returns a redirect to show route
A user gets a redirect and requests the show route
A server executes the show action
Apparently the route for review action (or as I called it above: a review route) doesn't exist in routes.rb. Add it.
UPD: Your routes file looks really odd, you seem to not follow a common practice to process one type of resources in one controller. Here, you probably need to add:
...
post 'search'
post 'review'
# ^ THIS ^
end
end
But you already process at least 3 types of resources in one controller: Users, Sessions and Restaurants. This might not be your fault if you were told to do so, but in either case it's not a proper way to structure an application.
Try:
<%= form_tag :action => 'review', :id => #restaurant.id do %>

Rails 4 Create form to update only one attribute

I have a user model, but I need to create a form to update only one attribute.
EDIT: I added the create_mailbox patch in :users resource but the form throws a undefined methodsettings_create_mailbox_path'` error. Can anyone give me some insight to how this member patch/resource routes work?
Here's the form:
<%= form_for #user, url: settings_create_mailbox_path(#user) do |f| %>
<%= f.text_field :rss_mailbox, autocomplete: 'off'%>
<button type="submit" class="button">Create Mailbox</button>
<% end %>
Here's the Users route:
resources :users, id: /.*/ do
member do
patch :settings_update, controller: :settings
patch :create_mailbox, controller: :settings
patch :view_settings_update, controller: :settings
patch :sharing_services_update, controller: :sharing_services
patch :actions_update, controller: :actions
end
end
And here's the settings route:
get :settings, to: 'settings#settings'
namespace :settings do
get :account
get :billing
get :import_export
get :feeds
get :help
post :update_credit_card
post :mark_favicon_complete
post :update_plan
post :font
post :font_increase
post :font_decrease
post :entry_width
end
It would depend on the attribute and what you're changing it to.
If it's a simple toggling of a boolean field, for example, you could get away with a link that fires off an ajax request, that makes the change and returns some HTML (eg. to update the link you clicked).
If it's something else, eg. a text field or a string or something, a form_for #user would be the typical way. But the form would only have one field, and the controller that processes the form post would have its strong parameters (or attr_accessible for Rails 3) set so that it will only accept data for that one field.
Was using the wrong route name. This was the right one:
create_mailbox_user_path
Rails 4 Use Strong Parameters to determine which attribute is allow to update like so:
def user_param
params.require(:user).permit(:attr)
end

Ruby on Rails: undefined method `' for #<#<Class:>>

I'm relatively new to rails and I've been struggling with this for a couple of days. I'd be much appreciated if you can see where I've gone wrong.
When I view the page in the web browser I get the following message:
Showing C:/Users/Matt/Documents/GitHub/Outputer/app/views/studies/index.html.erb where line #8 raised:
undefined method `studies_path' for #<#:0x6b03808>
8: <%= form_for #new_study do |f| %>
studies_controller:
def index
#line = current_user.lines.find_by_id(params[:line_id])
#machine = #line.machines.find_by_id(params[:machine_id])
#studies = #machine.studies.paginate(page: params[:page], :per_page => 10)
#new_study = #machine.studies.build
end
def create
#study = current_user.lines.machines.study.build(params[:study])
if #study.save
flash[:success] = "Study created"
else
flash[:error] = "Error : Invalid study description"
end
redirect_to :back
end
index.html
....
<section>
<%= form_for #new_study do |f| %>
<div class="field">
<%= f.text_field :description, placeholder: "New study description..." %>
</div>
<%= f.submit "Create", class: "btn" %>
<% end %>
</section>
....
Study Model
....
class Study < ActiveRecord::Base
belongs_to :machine
belongs_to :line
attr_accessible :avg_speed, :avg_uptime, :avg_yield, :description, :duration, :is_active, :start_time, :stop_time, :line_id
validates ....
has_many :events, dependent: :destroy
....
end
....
rake routes:
....
save_line_machine_study PUT /lines/:line_id/machines/:machine_id/studies/:id/save(.:format) studies#save {:has_many=>:machines}
line_machine_studies GET /lines/:line_id/machines/:machine_id/studies(.:format) studies#index {:has_many=>:machines}
POST /lines/:line_id/machines/:machine_id/studies(.:format) studies#create {:has_many=>:machines}
new_line_machine_study GET /lines/:line_id/machines/:machine_id/studies/new(.:format) studies#new {:has_many=>:machines}
edit_line_machine_study GET /lines/:line_id/machines/:machine_id/studies/:id/edit(.:format) studies#edit {:has_many=>:machines}
line_machine_study GET /lines/:line_id/machines/:machine_id/studies/:id(.:format) studies#show {:has_many=>:machines}
PUT /lines/:line_id/machines/:machine_id/studies/:id(.:format) studies#update {:has_many=>:machines}
DELETE /lines/:line_id/machines/:machine_id/studies/:id(.:format) studies#destroy {:has_many=>:machines}
....
routes.rb
resources :users
resources :lines, :has_many => :machines, only: [:index, :edit, :destroy, :show, :create] do
resources :machines, only: [:new, :create, :edit, :update] do
resources :studies
end
end
If I remove the form the page works fine which would suggest its in the form. I've tested the controller commands in the console and they all appear fine - I can create a new study object.
Thanks in anticipation
When you use form_for with a model instance, it defaults to the POST action for that controller which would be your studies_path. This is usually mapped to create in the controller.
From the looks of it, you need to add a route in routes.rb to handle that post request (see resources). You will also need a create method in your studies controller.
Here is a good guide for learning the basics of routing in rails.
Although a missing route is the most common reason for that (not-very-helpful) error, it can also be raised if one or both sides of a has_many/belongs_to relationship is missing or is incorrectly defined. Another place to look is a form field for an attribute that doesn't exist in the related model.
<%= form_for #new_study %> is equivalent to <%= form_for #new_study, url: studies_url %>. As your routes are defined differently, you need to pass the url you'd like to submit the form to to the url parameter (find form_for in the Rails API docs to see what other options it takes).
Three level deep nesting is kind of ugly to maintain, so I'd suggest the following:
resources :users
resources :lines do
resources :machines
end
resources :machines do
resources :studies
end
These shallow routes are much nicer to maintain. There's also a shallow: true option on nested resources calls, see the docs.
In your case:
# With the current setup
<%= form_for #new_study, url: line_machine_studies_path(#line, #machine)
# Same, my preference
<%= form_for [#line, #machine, #new_study] %>
# If you make your routes shallow,
# #line is not nescessary, as #machine holds all information about associations
<%= form_for #new_study, url: machine_studies_path(#machine) %>
# Same, my preference, what I would do
<%= form_for [#machine, #new_study] %>
General suggestions:
#study is preferred over #new_study. #study.new_record? will tell you whether the object is a new record if you need.
There's no has_many :... option on resources routes as far as I'm aware
Google rails shallow routes for more info. Keep nesting to two levels. Think about only what information you really require when creating objects and keep the URLs and url helpers as slim as possible.

modifying a user model with a rails form

total rails noob here so bear with me. I've been stuck for a long time trying to figure out how to make a page that allows a logged-in user to change, via text field, certain attributes of the user model. For instance, my user model has a number of "measurement" attributes that i'd like to directly modify via the page. My user model is running on Devise--I'm not sure if i'm doing the right thing by modifying the user model directly.
Here's my controller. I set it to find the second user because I was simply testing it out to see if it worked.
class MeasurementsController < ApplicationController
def index
#person = User.find(2)
end
end
Here's my index.html.erb:
<%= form_for #person do |f| %>
<%= f.label :style %>:
<%= f.text_field :style %><br />
<%= f.submit "Update"%>
<% end %>
However, it spits out this error:
NoMethodError in Measurements#index
undefined method `user_path'
Any help would be REALLY appreciated. Thanks so much in advance. Really lost here.
EDIT: Here's my routes.rb:
Contourfw::Application.routes.draw do
ActiveAdmin.routes(self)
devise_for :admin_users, ActiveAdmin::Devise.config
devise_for :users
root :to => 'contourfw#landingpage'
match "measurements" => "measurements#index"
match "styles" => "styles#index"
end
It looks like you need to add a resourceful route in your config/routes.rb:
resources :users
Update
By default that will assume a controller named users_controller.rb. If you want it to use the controller above, amend that to:
resources :users, :controller => "measurements"
See http://guides.rubyonrails.org/routing.html#customizing-resourceful-routes for more details.

no route matches create

HERE IS MY new.html.erb FILE BELOW
<%= form_for(:subject, :url => {:action => 'create'}) do |f| %>
i just want to insert a record in my database.
Here is my subjectscontroller.rb file below
end
Here is my route.rb file below
get "subjects/create"
When i run localhost:3000/subjects/new it runs perfectly. And then I try to insert a value through text boxes and when i click on Create subject button of my form it gives me no route matches create.Please solve my problem as soon as possible otherwise i am in deep trouble
You've defined a route which responds to an HTTP GET. When submitting the form, you send an HTTP POST. That's the source of your current error message.
Before panicking, take a few minutes to read through this Rails Guide on routing. I think it will help clarify how to proceed.
You should add the subjects to the routes as resources .
AppName::Application.routes.draw do
resources :subjects
root :to => "demo#index"
get ':controller(/:action(/:id(.:format)))'
end
Your controller should be like this
def create
#subject = Subject.new(subject_params)
if #subject.save
redirect_to(:action => 'list')
else
render('new')
end
end
private
def subject_params
params.require(:subject).permit(:id, :name, :position, :visible)
end
It should work.

Resources