I have a has_one / belongs_to association between two models -> User and ContactCard. While I am able to create a contact card for a user, whenever I try to edit the card the create action is called from the ContactCardsController rather than update (I can tell because I have different success messages on each). It changes the attributes of the contact card just fine I have to say. I'm mostly happy it's working but would rather patch up any gaps in my understanding of rails paths and associations. What am I missing? Why isn't it using the action I expect? Also if you know of any relevant examples on the web or on github I could study up on, I'm all ears. Thanks!
Contact Cards Controller...
class ContactCardsController < ApplicationController
def create
current_user.build_contact_card(params[:contact_card])
if current_user.contact_card.save
flash[:success] = "Contact Card created!"
redirect_to '/account'
else
flash[:error] = "Fail!"
redirect_to '/account'
end
end
def update
if current_user.contact_card.update_attributes(params[:contact_card])
flash[:success] = "Profile updated."
redirect_to '/account'
else
flash[:error] = "Fail!"
redirect_to '/account'
end
end
Link to edit form...
<%= link_to "Edit Profile", edit_user_contact_card_path(current_user) %>
Edit form...
<%= form_for [current_user, current_user.build_contact_card], :url => user_contact_card_path(current_user) do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
<%= f.submit "Save Contact Details", :class => "btn btn-large btn-primary" %>
<% end %>
Relevant Routes...
resources :users do
resource :contact_card
.....
The User model has_one :contact_card and the ContactCard model belongs_to:user
<%= form_for [current_user, current_user.build_contact_card], :url => user_contact_card_path(current_user) do |f| %>
This is building a new contact card every time you edit! Change it to
<%= form_for [current_user,contact_card], :url => user_contact_card_path(current_user) do |f| %>
You'd want the build_contact_card in the create action of User controller probably
Related
I'm learning Rails so please pardon my amateur mistakes, but I've been stuck for about an hour or two and have made negative progress.
Goal:
From the user profile view, link to a form that allows this user
to change their email. Once the form is submitted, it should trigger
an appropriate method within the user controller.
I can handle the rest, I just haven't managed to connect the parts mentioned above. I have been reading railsTutorial.org and guides.rubyonrails.org but haven't been able to understand routing form_for() sufficiently.
User Profile Link:
<%= #user.email %> <%= link_to "(change)", email_path(#user) %>
Routes
Rails.application.routes.draw do
get 'email' => 'users#email_form'
post 'email' => 'users#changeemail'
end
User Controller
class UsersController < ApplicationController
def email_form
#user = User.find(params[:id])
end
def changeemail
#user = User.find(params[:id])
redirect_to #user
end
end
Currently the error I get once I click the link is Couldn't find User with 'id'= which I assume means user ID is nil because I fail at passing it.
I would greatly appreciate an explanation of what data is being passed through this workflow so I can be a better developer, thank you very much!
EDIT:
The form itself:
<%= form_for(#user, url: user_path(#user)) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :new_email %>
<%= f.text_field :new_email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.submit "Submit New Email", class: "btn btn-primary" %>
<% end %>
You could do this (note :id and "as"):
Rails.application.routes.draw do
get 'email/:id' => 'users#email_form', as :email
post 'email/:id' => 'users#changeemail', as :change_email
end
The :id is then expected to be part of the route.
Alternatively, pass the id directly when generating the url:
<%= #user.email %> <%= link_to "(change)", email_path(id: #user) %>
This will make a call to "UsersController#update"
<%= form_for(#user, url: user_path(#user)) do |f| %>
...instead you would use something like::
<%= form_for(#user, url: change_email_path(#user), method: :put) do |f| %>
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for
...but in terms of best practices, if you want to do separate flow for email updating, you could be more explicit in treating it as a different resource (even though it's still the user record).
For example, you could map these to an explicit 'resource' with a #show and #update action...
Routes:
resources :user_emails, only: [:show, :update]
Controller:
class UserEmailsController < ApplicationController
def show
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
redirect_to #user # goes back to UsersController#show
end
end
Then the route would be:
<%= #user.email %> <%= link_to "(change)", user_email_path(#user) %>
In this case we don't have to say (id: #user) since the 'resource' generates the right urls for you.
...and this would be
<%= form_for(#user, url: user_email_path(#user), method: :post) do |f| %>
Im writing a game on rails, and am trying to allow a user to create their mine (its a mining game).
I have a table for the users, and a table for mines.
Each user has a ref. ID on their entry, pointing to their mine's ID in the mine table.
I'm getting an error when I try to visit /users/1/mines/new.
undefined method `mines_path'
I can't figure out why.
form in New:
<%= form_for [#mine] do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
Controller:
def new
#user = User.find(params[:user_id])
#mine = #user.mines.new
end
def create
#mine = #user.mines.create(mine_params)
if #mine.save
redirect_to users_mines_path
else
render new_mines_path
end
end
routes:
root 'welcome#index'
resources :sessions, only: [:create]
resources :users do
resources :mines
end
resources :tools, only: [:create]
How can I create a new mine THROUGH the user? Am I doing this correctly in my controller?
Thanks!
In your routes you have mines nested inside users so you need to change your form to something like this:
<%= form_for [#user,#mine] do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
OR
You can specify url option with your path:
<%= form_for #mine, url: user_mines_path(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %><br>
<p>Depth: <%= #mine.depth %></p>
<%= f.submit "Submit", id: "submit" %>
<% end %>
For details on forms refer to Form Helpers
Also as #Vimsha pointed out in your controller you need to use .new instead of .create as create will initialize and save your your mine.
def create
#mine = #user.mines.new(mine_params)
if #mine.save
redirect_to user_mines_path
else
render new_user_mine_path
end
end
#user.mines.create will create the mine. So use #user.mines.new
named route for mine index will be user_mines_path
named route for mine show will be user_mine_path(#mine)
named route for new mine will be new_user_mine_path
Contoller:
def create
#mine = #user.mines.new(mine_params)
if #mine.save
redirect_to user_mines_path
else
render new_user_mine_path
end
end
I am new to ruby, trying to follow the official documentation and create a basic form for creating a post:
<%= form_for #post, :url => { :action => "create" }, :html => {:class => "nifty_form"} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :entry, :size => "60x12" %>
<%= f.submit "Create" %>
<% end %>
The form is successfully adding an entry to the database, but an empty one, I think I must be missing something in my controller? Do I need to pass the variables somehow?
def create
#post = Main.create
end
A basic create action can look like this. You first initialize a new post. Depending on if it successfully saves you proceed.
# app/controllers/posts_controller.rb
class PostsController < ActionController::Base
def create
#post = Post.new(params[:post])
if #post.save
redirect_to #post, notice: 'Post has been created.'
else
render :new
end
end
end
You can shorten your form.
<%= form_for #post do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.text_area :entry, :size => "60x12" %>
<%= f.submit %>
<% end %>
You can see excellent example code along these lines when you generate a scaffold, so I would encourage you to try $ rails generate scaffold Post title body:text and learn by example.
Submitting a form passes the values entered into that form (along with some other information) to the controller as a hash called "params" - the params will contain a block labelled with the name of the form, in this case "post".
You need to use the post block from params in the creation of the new object.
def create
#post = Main.new(params[:post])
if #post.save
# handles a successful save
else
# handles validation failure
end
end
Try:
#post = Main.new(params[:post])
#post.save
There is a lot of discussion around Rails 3 STI and how to use forms, but no definitive answers on StackOverflow. I seem to have run into a similar issue and have attempted the other solutions with no results.
I have two models with the following inheritance set up:
User.rb
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name, #more follows
Waiter.rb
class Waiter < User
On the form at /waiters/users/[:id]/edit, I am attempting to create a form for editing the waiter. However, I am getting the following error upon loading the edit view:
undefined method `waiter_path' for #<#<Class:0x007fbd08cef9d8>:0x007fbd09532fa0>
This is my controller found at /app/controllers/admin/waiters/users_controller.rb:
def edit
form_info
#user = Waiter.find(params[:id])
end
def update
#user = Waiter.find_by_id(params[:id])
if #user.update_attributes(params[:user])
flash[:notice] = "Successfully assigned Waiter."
redirect_to admin_waiters_users_url()
else
form_info
render :action => 'edit'
end
end
And this is the form located in the edit view:
<%= simple_form_for #user do |f| %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :email %>
<%= button_tag(type: 'submit', class: "btn btn-primary") do %>
<i class="icon-ok icon-white"></i> Save
<% end %>
<% end %>
What am I doing wrong here with STI and routing?
UPDATE: here is my rake routes:
admin_waiters_users GET /admin/waiters/users(.:format) admin/waiters/users#index
POST /admin/waiters/users(.:format) admin/waiters/users#create
new_admin_waiters_user GET /admin/waiters/users/new(.:format) admin/waiters/users#new
edit_admin_waiters_user GET /admin/waiters/users/:id/edit(.:format) admin/waiters/users#edit
admin_waiters_user GET /admin/waiters/users/:id(.:format) admin/waiters/users#show
PUT /admin/waiters/users/:id(.:format) admin/waiters/users#update
You should use your routes to see what routes you have defined:
You can run your routes with:
rake routes
I can not see your routes but perhaps waiter_path does not exist.
Perhaps is user_waiter_path(#user) or other router.
Please paste your routes for that the people on stackoverflow can help to you.
I can not see the route waiter_path on your routes, If you have waiter_path inside of your edit view you have remove it.
Also, you can specify what controller and action hit,
<%= simple_form_for #user, :url => { :controller => "admin/waiters/users", :action => "update"} do |f| %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :email %>
<%= f.button :submit, "save", class: "btn btn-primary"%>
<% end %>
You can check with f.button instead button_tag
Regards!
Woo. My first question.
I have a feeling I'm overlooking something pretty basic in the construction of my form. I'm using attachment_fu and can't get this form to pass anything besides the file data. A user has_many profiles and a profile has_many documents.
My form looks like this:
<%= error_messages_for :document %>
<% form_for([#user, #profile, #document], :html => {:multipart => true }) do |f| -%>
<p>
<label for="document">Upload A document:</label>
<%= f.file_field :uploaded_data %>
</p>
<%= f.label :description%>
<%= f.text_field :description%>
<p>
<%= submit_tag 'Upload' %>
</p>
<% end -%>
And here's the controller:
before_filter :require_user, :get_profile
def new
#document = #profile.documents.build
end
def create
#document = #profile.documents.build(params[:document])
if #document.save
flash[:notice] = 'Your document was successfully created.'
redirect_to document_url(#document)
else
render :action => :new
end
end
private
def get_profile
#user = current_user
#profile = #user.profiles.find(params[:profile_id])
end
The logs show all the image data getting posted, but I cannot pass the description or, more importantly, the profile_id, which is the foreign key in my document model. I was stuck on this all night, and can't think of anything fresh this morning. Any help would be great.
For the profile_id you will need something like:
<%= f.hidden_field :profile_id %>
Which in your controller you will get at using params[:document][:profile_id] if needed.
Although from trying to guess at what your code is doing, I suspect that params[:profile_id] is already set from whatever route got you to this controller.
I am not sure why you aren't seeing anything for the description. It should be coming into your controller as params[:document][:description].