Right now I'm building a project management app in rails, here is some background info:
Right now i have 2 models, one is User and the other one is Client. Clients and Users have a one-to-one relationship (client -> has_one and user -> belongs_to which means that the foreign key it's in the users table)
So what I'm trying to do it's once you add a client you can actually add credentials (add an user) to that client, in order to do so all the clients are being displayed with a link next to that client's name meaning that you can actually create credentials for that client.
So in order to do that I'm using a helper the link to helper like this.
<%= link_to "Credentials",
{:controller => 'user', :action => 'new', :client_id => client.id} %>
Meaning that he url will be constructed like this:
http://localhost:3000/clients/2/user/new
By creating the user for the client with he ID of 2.
And then capturing the info into the controller like this:
#user = User.new(:client_id => params[:client_id])
EDIT: This is what i currently have in my View/Controller and Routes
I keep getting this error: No route matches "/clients//user" with {:method=>:post}
Routes
ActionController::Routing::Routes.draw do |map|
map.resources :users
map.resources :clients, :has_one => :user
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
Controller
class UsersController < ApplicationController
before_filter :load_client
def new
#user = User.new
#client = Client.new
end
def load_client
#client = Client.find(params[:client_id])
end
def create
#user = User.new(params[:user])
#user.client_id = #client.id
if #user.save
flash[:notice] = "Credentials created"
render :new
else
flash[:error] = "Credentials created failed"
render :new
end
end
View
<% form_for #user, :url => client_user_url(#client) do |f| %>
<p>
<%= f.label :login, "Username" %>
<%= f.text_field :login %>
</p>
<p>
<%= f.label :password, "Password" %>
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation, "Password Confirmation" %>
<%= f.password_field :password_confirmation %>
</p>
<%= f.submit "Create", :disable_with => 'Please Wait...' %>
<% end %>
Your form tag is wrong, you are posting to /users without the :client_id.
Try this:
<% form_for #user, :url => {:controller => 'users', :action => 'new', :client_id => #client.id} do |f| >
Alternatively, you could use nested resources:
config/routes.rb
map.resources :clients do |clients|
clients.resources :users
end
Controller
class UsersController < ApplicationController
before_filter :load_client
def load_client
#client = Client.find(params[:client_id])
end
# Your stuff here
end
View
<% form_for [#client, #user] do |f| %>
I solved this by using nested attributes, by including the user model, when creating the client. And it works flawlessly.
In case any of you guys need more info here's the two screencasts that helped me come up with as solution:
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/196-nested-model-form-part-2
Related
I'm trying to add edit functionality to my web app, and am having some trouble. The error page I get back when I try to complete an edit of my Request object indicates that it couldn't find the right route, but the same error page contains a list of routes which includes the route it's looking for. So I'm a bit flummoxed.
The "new" method is almost identical to this edit method and the pages are almost identical as well.
The error page begins No route matches [POST] "/requests/19/edit" and then, partway down the route listing, I see this:
requests_path GET /requests(.:format) requests#index
POST /requests(.:format) requests#create
new_request_path GET /requests/new(.:format) requests#new
edit_request_path GET /requests/:id/edit(.:format) requests#edit
request_path GET /requests/:id(.:format) requests#show
PATCH /requests/:id(.:format) requests#update
PUT /requests/:id(.:format) requests#update
DELETE /requests/:id(.:format) requests#destroy
So Rails seems to be generating a request_path which expects a PATCH, not a POST, right?
routes.rb
Rails.application.routes.draw do
root "pages#index"
resources :destinations
resources :users
resources :manifests
resources :requests
:
request.rb
class Request < ActiveRecord::Base
validates_presence_of :justification
validates_presence_of :required_by
belongs_to :user
belongs_to :manifest
belongs_to :network
has_many :uploaded_files
scope :sorted, lambda{ order("required_by") }
end
edit.html.rb
<% #page_title = "Update Request" %>
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div class="requests edit">
<h2>Update Request</h2>
<%= form_for :request, url: request_path(#request) do |f| %>
<%= render(:partial => "form", :locals => {:f => f}) %>
<div class="form-buttons">
<%= submit_tag("Update Request") %>
</div>
<% end %>
</div>
requests_controller.rb
def update
#request = Request.find(params[:id])
p = {'file' => params[:request][:uploaded_file], 'request_id' => #request.id}
uf = UploadedFile.create(p)
if #request.update_attributes(request_params)
flash[:notice] = "Request updatred succesfully"
redirect_to :action => 'show', :id => #request.id
else
render 'edit'
end
end
What have I missed?
Change
<%= form_for :request, url: request_path(#request) do |f| %>
to
<%= form_for :request, url: request_path(#request), method: :patch do |f| %>
in your edit.html.erb
form_for(as you are using it) sets POST as default HTTP verb. You need to alter it by setting method :patch which responds to the update action.
You can simplify it to just
<%= form_for #request do |f| %>
Check the APIdoc for more Info.
Hello i'm new one in ruby on rails. I have strange problem. I use some tutorial and get error which i shouldn't get.
I have controller
class DiaryController < ApplicationController
before_action :authenticate_user!
respond_to :html, :xml, :json
respond_to :js, :only => [:create, :update, :destroy]
def create
#record = Record.create(record_params)
#record.userId=current_user.id
if request.xhr? || remotipart_submitted?
sleep 1 if params[:pause]
render :layout => false, :template => (params[:template] == 'escape' ? 'comments/escape_test' : 'diary/create'), :status => (#record.errors.any? ? :unprocessable_entity : :ok)
else
redirect_to diary_path
end
end
def add
#record = Record.new
#respond_with(#record, :layout => false)
respond_with do |format|
format.html { render :layout => ! request.xhr? }
end
end
# PUT /comments/1
# PUT /comments/1.xml
def update
#record = Record.find(params[:id])
respond_with do |format|
format.html{ redirect_to #record }
end
end
def delete
#comment = Comment.destroy(params[:id])
end
def edit
#record = Record.find(params[:id])
end
def index
#records = Record.where(userId: current_user.id)
end
private
def record_params
params.require(:record).permit(:photo, :comment, :date, :photo_cache)
end
end
Have view
<h1 align="centre">
Добавить запись
</h1>
<%= render 'form' %>
<%= link_to 'Отмена', diary_path, :id => 'cancel-button' %>
and
<%= form_for(#record, :remote => (params[:action] == 'add' ? true : false)) do |f| %>
<fieldset>
<div class="field">
<%= f.label :date, :class => 'required' %><br />
<%= f.date_select :date %>
</div>
<div class="field">
<%= f.label :comment %><br />
<%= f.text_area :comment %>
</div>
<div class="field">
<%= image_tag(#record.photo_url(:thumb)) if #record.photo? %><br />
<%= f.label :photo %><br/>
<%= f.file_field :photo %><br/>
<%= f.hidden_field :photo_cache %>
</div>
</fieldset>
<table>
<tr>
<td>
<div class="actions">
<%= f.submit "Добавить", :data => {:'disable-with' => "Submitting..."} %>
</div>
</td>
<td>
<%= link_to 'Отмена', diary_path, :id => 'cancel-button' %>
</td>
</tr>
</table>
And get ActionView::Template::Error (undefined method `records_path' for #<#:0x000000054461c8>): error on "<%= form_for(#record, :remote => (params[:action] == 'add' ? true : false)) do |f| %>" line. Even records_path i did'n use.
I Have routes
devise_for :users
get 'welcome/index'
root 'welcome#index'
get 'diary' => 'diary#index'
get 'diary/add_record', to: 'diary#add', as: 'add_record'
post 'diary/add_record', to: 'diary#create'
get 'diary/edit_record/:id', to: 'diary#edit'
delete 'diary/edit_record/:id' => 'diary#delete
And and try to use add_record route. Maybe it would be better to use resources :records.But i want to figure out why my routes doesn't work.
view name "diary".
Because you're new to RoR, let me explain why you're receiving the error
form_for
form_for is the likely reason why you're receiving this error (oh, I just saw it actually states this is where the error occurs - sweet)
The problem you have is that form_for is meant as a way to render a form around an ActiveRecord object. It's mean to give some semi-persistence to the data, by using AR in both the new and create actions (allowing you to show the in-putted data on the form after submission)
When you pass an object to form_for, Rails automatically "builds" the form from the ActiveRecord object, one of the options it uses being the url
--
Routes
The problem you have is the object you pass to the form_for takes the model_name attribute to build the route. This means if you want to use the form_for method by just passing an object, it's going to look for routes pertaining directly to that object
If you don't have any [model]_path route set up, you'll likely receive the error you're getting. The fix firstly involves the routes, and secondly involves the controller:
#config/routes.rb
root 'welcome#index'
devise_for :users
resources :diary, path_names: { new: "add_record", create: "add_record", edit: "edit_record", destroy: "edit_record" }
resources :welcome, only: :index
This is down to the idea that Rails' routing structure is built around resources - every route you have should lead to a specific controller action. Whilst including custom actions is completely fine, you have to appreciate that the basis of the routing structure is to construct resourceful routing, which essentially means that Rails perceives every controller / model to have corresponding routes:
--
URL
The second thing to observe is the url of the form
If you have your routes set up as above, and if your routing structure differs from your model structure (different names), you'll want to use the following setup to define the url explicitly:
<%= form_for #record, url: your_custom_path do |f| %>
Routes
resources :locations, :only => [:new, :create]
Controller
class LocationsController < ApplicationController
def new
#location = Location.new
end
def create
#location = Location.new(location_params)
if #location.save
flash[:notice] = 'Created location successfully'
redirect_to new_location_path
else
flash[:notice] = 'Invalid information. Please try again'
render :new
end
end
private
def location_params
params.require(:location).permit(:name, :street, :city, :state)
end
end
Error message when I click save.
ActionController::RoutingError:
No route matches [POST] "/locations/new"
view
<%= simple_form_for :locations do |form| %>
<%= form.input :name %>
<%= form.input :street %>
<%= form.input :city %>
<%= form.input :state %>
<%= form.submit 'Create location' %>
<% end %>
Using capybara to test that when I click on save it creates a new location. I'm not quite sure why it doesn't know what the post route is because I have the new and create routes. If I put a binding.pry right underneath the create method it doesn't get called. So my create method is not being called for some reason.
EDIT:
Rake Routes
locations POST /locations(.:format) locations#
new_location GET /locations/new(.:format) locations#new
A resource normally GETs to new and POSTs to create. So your form is probably submitting back to the new actions instead of submitting to the create action.
Here's the guide for this: http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
The problem was in the views.
<%= simple_form_for :locations do |form| %>
<%= form.input :name %>
<%= form.input :street %>
<%= form.input :city %>
<%= form.input :state %>
<%= form.submit 'Create location' %>
<% end %>
I was calling on locations symbol when I should have been calling on the instance variable #location from the controller.
The actual problem was that rails 3.2.12 doesn't take private params
Using resources, the new action should be fetched with GET instead of POST. create will be POST. Check your rake routes
There are similar questions but I've gone over them and none of them have applied.
I am using Devise and Devise invitations. Rails 3.2.6.
The tricky thing is I have two user models. User and a single table inheritance setup where Artist inherits from User. I have two invitations controllers to allow sending invitations separately to both Users and Artists.
The issue right now is that artists are not able to accept their invitations. Upon form submit of updating their password, they get a 406 unacceptable error.
Relevant Code:
Routing:
devise_for :users,
:class_name => User,
:controllers => { :invitations => 'user/invitations' }
namespace :artist do
# Special route for devise, artists invitation
devise_scope :user do
resource :invitation, :controller => :invitations, :only => [:create, :new, :update] do
get :accept, :action => :edit
end
end
end
Artist invitations controller
class Artist::InvitationsController < Devise::InvitationsController
respond_to :html
# PUT /resource/invitation
def update
self.resource = Artist.accept_invitation!(params[resource_name])
if resource.errors.empty?
resource.pending
flash[:notice] = "Welcome, complete your artist agreement to get started"
sign_in(:user, resource)
respond_with resource, :location => after_accept_path_for(resource)
else
respond_with_navigational(resource){ render :edit }
end
end
end
Form description. edit.html.erb.
<%= form_for resource, :as => resource_name, :url => artist_invitation_path(resource_name), :html => { :method => :put } do |f| %>
<%= f.hidden_field :invitation_token %>
<%= f.label :password, class: 'control-label' %>
<%= f.password_field :password, :placeholder => 'Enter a password' %>
<%= f.label :password_confirmation, class: 'control-label' %>
<%= f.password_field :password_confirmation, :placeholder => 'Confirm your password' %>
<%= f.submit "Set my password", :'data-disable-with' => "Hang on..." %>
<% end %>
Accept headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:236
Content-Type:application/x-www-form-urlencoded
Returns
Request URL:http://localhost:3000/artist/invitation.user
Request Method:POST
Status Code:406 Not Acceptable
I can see that something in the format must be off because of the response adding in that .user to the end. I can not for the life of me see why or where that is happening. Please let me know if there's any info I left out which could help.
Got it, finally.
The key is to look precisely at what resource_name is giving you throughout the form and controller actions. In my case it continued to fallback to :user when it needed to be :artist and as Frost mentioned in a comment, the generated form html changes greatly if you pay attention to where resource_name is used. The update action in the controller needed to be overridden to use :artist directly and the form_for needed to be tweaked to remove resource_name from arguments and the :as argument.
I'm super new to Ruby on Rails. I'm trying to make an authentication system using Authlogic (following this tutorial). The error that I'm getting is right after I submit the login form:
No route matches "/user_sessions/%23%3CUserSession:0x103486aa8%3E"
Surprisingly the URL of the page right after the form is submitted which also brings up the error is:
http://localhost:3000/user_sessions/%23%3CUserSession:0x103486aa8%3E
I have no idea what I have done wrong and where that weird UserSession code thing is coming from!!!
This is how my login form looks like:
<% form_for #user_session do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :username %><br />
<%= f.text_field :username%>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
</p>
<p><%= f.submit "Submit" %></p>
<% end %>
Here is my UserSession class:
class UserSession < Authlogic::Session::Base
def to_key
new_record? ? nil : [ self.send(self.class.primary_key) ]
end
end
and the create action of my UserSessionController:
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
flash[:notice] = "Login successful!"
redirect_back_or_default root_path
else
render :action => :new
end
end
"redirect_back_or_default" method in ApplicationController:
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
And lastly everything related to user_sessions in routes.rb:
resources :user_sessions
match 'login' => "user_sessions#destroy", :as => :login
match 'logout' => "user_sessions#destroy", :as => :logout
These are the codes that I thought could be involved in getting that error. If I should add some more code to make it more clear please let me know.
Ok, first, you have a bad route:
match '/login', :to => 'user_sessions#new', :as => 'login'
note the new instead of destroy
also, the to_key is not needed in later versions - I'm using rails 3 and don't have it in my UserSession Model.
Definitely need to change your route to not match login to destroy.
Here's the route setting I have... (from "Agile Web Development with Rails" example).
controller :user_sessions do
get 'login' => :new
post 'login' => :create
delete 'logout' => :destroy
end