I am getting started with rails, so this is a fairly basic question. I am trying to render a login form (authlogic) in the homepage, using this code:
views/home/index.html.haml:
%p
This is the home page...!
- if current_user
- else
= render :template => 'user_sessions/new'
user_sessions_controller:
class UserSessionsController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
def new
#user_session = UserSession.new
end
def create
#user_session = UserSession.new(params[:user_session])
if #user_session.save
flash[:notice] = "Login successful!"
redirect_back_or_default user_controls_url
else
render :action => :new
end
end
def destroy
current_user_session.destroy
flash[:notice] = "Logout successful!"
redirect_back_or_default home_url
end
end
views/user_sessions/new.html.haml
= form_for #user_session, :url => {:action => "create"} do |f|
= f.error_messages
%div
= f.label :login
= f.text_field :login
%div
= f.label :password
= f.password_field :password
%div
= f.check_box :remember_me
= f.label :remember_me
%div
= f.submit "Login"
models/user_session.rb
class UserSession < Authlogic::Session::Base
def to_key
new_record? ? nil : [ self.send(self.class.primary_key) ]
end
httponly true
secure true
end
When I visit the homepage, I get:
ActionView::Template::Error (undefined method `model_name' for NilClass:Class):
1: = form_for #user_session, :url => {:action => "create"} do |f|
2: = f.error_messages
3: %div
4: = f.label :login
app/views/user_sessions/new.html.haml:1:in `_app_views_user_sessions_new_html_haml___182031841_97682750'
app/views/home/index.html.haml:6:in `_app_views_home_index_html_haml__679857083_97787190'
What am I doing wrong, and how do I fix it?
Thanks a lot for your help.
In your code, #user_session is being created when you visit the new action that is connected to user_sessions/new; it is not created when you go to the index action.
When you render the user_sessions/new template from the index action, ERB/HAML is looking for an instance of #user_session and cannot find it, hence the error.
So, you could instantiate #user_session like this:
#Note: The <%%> is ERB code (please adjust it for the syntax used in HAML)
<% #user_session = UserSession.new if #user_session.nil? %>
= form_for #user_session, :url => {:action => "create"} do |f|
...
Or, you can also do it in the index action itself, though it would be better to keep it out from the index action and instead do it as above (eg. what if you want to render the template from some other action as well - then you would be duplicating code unnecessarily)
Related
I've created a contact form in Rails 4 with this example.
But I want to display this contact form on the main/show page of my application. How can I do this?
routes.rb.
Rails.application.routes.draw do
resources :projects
resources :contacts, only: [:new, :create]
get 'welcome/index'
root 'welcome#index'
end
contacts_controller.rb
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact = Contact.new(params[:contact])
#contact.request = request
if #contact.deliver
flash.now[:error] = nil
else
flash.now[:error] = 'Cannot send message.'
render :new
end
end
end
Thanks.
And easy and clean way would be to create a partial
_contact_form.html.erb (Partials always starts with an underscore)
.container
%h1 Contact
= simple_form_for #contact, :html => {:class => 'form-horizontal' } do |f|
= f.input :name, :required => true
= f.input :email, :required => true
= f.input :message, :as => :text, :required => false, :input_html => {:rows => 10}
.hidden
= f.input :nickname, :hint => 'Leave this field blank!'
.form-actions
= f.button :submit, 'Send message', :class=> "btn btn-primary"
Then, in your index page:
<%= render "contacts/contact_form" %>
and in your controller index action( I don't know if 'welcome/index' is on project's controller or contacts controller)
def index
#your code
#contact = Contact.new
end
Finally, you seem quite new to rails, I'd like to recommend a free Ruby on Rails Tutorial
I'm making contact form on simple site using ruby on rails. Problem is following. I have main controller StaticPages that makes plain html with header and footer. Now i made controller Contacts that displays view with simple contact form on separate url. When i try to add this form to my contact page from StaticPages it doesn't work. i don't know how to tell rails that this form should find method not from StaticPages controller but from Contacts controller.
Here is my code:
Contacts controller
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact = Contact.new(params[:contact])
#contact.request = request
if #contact.deliver
flash.now[:notice] = 'Thanks!'
else
flash.now[:error] = 'Error!'
render :new
end
end
end
StaticPages controller
class StaticPagesController < ApplicationController
def home
end
def about_us
end
def contact_us
end
end
and here is the form i need to work on StaticPage contact_us
<div align="center">
<h3>Send us message</h3>
<%= simple_form_for #contact, :html => {:class => 'form-horizontal' } do |f| %>
<%= f.input :name, :required => true %>
<%= f.input :email, :required => true %>
<%= f.input :message, :as => :text, :required => true %>
<div class= "hidden">
<%= f.input :nickname, :hint => 'Leave this field blank!' %>
</div>
<div>
</br>
<%= f.button :submit, 'Send', :class=> "btn btn-primary" %>
</div>
<% end %>
</div>
I guess I need to tell rails that this form should be looking for particular controller, but I don't know how.
Please help.
This isn't quite what you're looking for but it should work the way you want, you should have a contacts_helper.rb, that should look like this
module ContactsHelper
def contact_us
#contact = Contact.new
end
end
In your partial you'll want
<%= simple_form_for contact_us, :html => {:class => 'form-horizontal' } do |f| %>
And finally you need to include your helper, in application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
...
include ContactsHelper
...
end
One easy option would be to have the StaticPages contact_us action redirect_to new_contact_url (assuming that form lives at app/views/contacts/new.html.erb)
Alternatively, you could put the form in app/views/shared/_new_contact.html.erb, then put in #contact = Contact.new in your contact_us action, and have the contact_us template render partial: "shared/new_contact", locals: { :contact => #contact }.
models/lead.rb
class Lead < MailForm::Base
attribute :fullname
def headers
{
:subject => "My Contact Form",
:to => "callumshorty#hotmail.com",
:from => "admin#uk-franchise.co.uk"
}
end
end
controllers/lead_form_controller.rb
class LeadFormController < ApplicationController
def new
#lead = Lead.new
end
def create
#lead = Lead.new(params[:lead_form])
#lead.request = request
#lead.deliver
end
end
routes.rb
resources :lead_form
views/listings/show.html.erb
<%= form_for #lead, :url => url_for(:controller => 'lead_form', :action => 'new') do |lead| %>
<%= lead.text_field :fullname %>
<%= lead.submit %>
<% end %>
The error when trying to access the show page:
First argument in form cannot contain nil or be empty
On line:
<%= form_for #lead, :url => url_for(:controller => 'lead_form', :action => 'new') do |lead| %>
Any help would be super appreciated, can't stand these mailers :(
Your #lead needs to be initialised in the ListingsController#show action, since your lead form is in that view. Try adding #lead = Lead.new in the ListingsController#show method.
I'm having a problem getting my first app (I'm a total newbie) to save a new associated record. I have two models (users and pictures) with a has_many/belongs_to association. I have set up the userController so that it can create a new picture as below:
def new_picture
#user = User.find(current_user.id)
#picture = #user.pictures.build
end
def create_picture
#user = User.find(params[:id])
#picture = #user.pictures.build(params[:picture])
if #picture.save
flash[:notice] = "Your picture was successfully added."
redirect_to :action => 'show', :id => #user.id
else
render :template => "new_picture"
end
end
and I use
<%= link_to("add picture", :action => 'new_picture', :id => #user.id) if current_user %>
to add a new one. But I'd also like to be able to edit. So I updated the usercontroller with some new code:
def edit_picture
#user = User.find(current_user.id)
#picture = #user.pictures.find(params[:id])
end
# When the user clicks the save button update record
def update_picture
#user = User.find(current_user.id)
#picture = #user.pictures.find(params[:picture])
respond_to do |format|
if #picture.update_attributes(params[:picture])
flash[:notice] = "Your picture was successfully updated."
redirect_to :action => 'show', :id => #user.id
else
render :template => "new_picture"
end
end
end
and added the edit link to show.erb:
<%= link_to("edit picture", :action => 'edit_picture', :id => picture.id) if current_user %>
It loads the edit form fine, with the data all in the right place, but on save all it's doing is giving me the error 'ArgumentError in UsersController#update_picture' with a bunch of Unknown key(s) from my pictures table.
Could somebody explain why? I feel like there is one piece of the jigsaw I haven't quite understood here....
Thanks in advance!
UPDATE: View code is as follows:
<h1>New picture for <%= #user.name %></h1>
<% form_for :picture, #picture, :html => { :multipart => true }, :url => {:action => 'update_picture', :id => #user.id} do |f| %>
Can't seem to see your problem in the view code, however you can do the same thing more elegantly (RESTful) as a nested route. That way you might be able to see the problem more clearly.
config/routes.rb:
resources :users do
member do
resources :pictures
end
end
app/controllers/pictures_controller.rb:
class PicturesController < ApplicationController
before_filter :find_picture, :only => [:edit, :update]
def edit
end
def update
if #picture.update_attributes params[:picture]
flash[:notice] = "Your picture was successfully updated."
redirect_to user_path(current_user)
else
render :edit
end
end
protected
def find_picture
#picture = current_user.pictures.find params[:id]
end
end
app/views/pictures/edit.html.erb:
<%= form_for [current_user, #picture] do |f| %>
<!-- some stuff -->
<% end %>
and to link to your edit form:
<%= link_to_if current_user, 'edit picture',
edit_user_picture_path(:user => current_user, :id => picture) %>
I suggest adding 'accepts_nested_attributes_for :pictures to the user model, and then do
<%= form_for #user do |form| %>
.. user fields
<%= form.fields_for :pictures do |picture_form| %>
.. picture fields
<% end %>
<%= form.submit %>
<% end %>
in the view.
Another option is to create a new controller for the pictures. That may be simpler.
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