How do I change the form rendered by Rails? - ruby-on-rails

I have two classes, User and Contact. A User has many contacts, and a Contact belongs to a user. In the user's show view, I have:
<%= link_to 'Add Contact', :controller => "contacts", :action => "new", :user => #user.id %>
Then, in the contact's controller, under the new action, I have:
#user = User.find(params[:user])
#contact = Contact.new
#contact.user = #user
When the new contact form renders, it has #<User:0x4c52940> in the User field already. However, when I go to submit the form, I get the error: User(#39276468) expected, got String(#20116704).
The problem is that, when create gets called, Ruby takes everything in the form and overwrites the fields in the new Contact. So: how can I change the form to remove the User field, so that the User is not overwritten with the string?
Edit:
My Contact's new.html.erb has this:
<%= render 'form' %>
<%= link_to 'Back', contacts_path %>
Contact's controller:
def new
#user = User.find(params[:user])
#contact = Contact.new
#contact.user = #user
respond_to do |format|
format.html # new.html.erb
format.json { render json: #contact }
end
end
and
def create
#contact = Contact.new(params[:contact])
respond_to do |format|
if #contact.save
format.html { redirect_to #contact, notice: 'Contact was successfully created.' }
format.json { render json: #contact, status: :created, location: #contact }
else
format.html { render action: "new" }
format.json { render json: #contact.errors, status: :unprocessable_entity }
end
end
end

I believe you misuse create action of the controller. Essentially its content should be like so
def create
#user = User.find(params[:user_id])
contact = #user.contacts.build(params[:contact])
if contact.save
flash[:alert] = 'New contact is created'
redirect_to contacts_path(contact)
else
flash.now[:error' = 'Error creating contract'
render :action => :new
end
end
So +1 for the previous answer - show you controller and new form code

Related

Setting an object attribute from a hidden field Ruby on Rails

I'm trying to update an Idea attribute challenge_id through a hidden form field. Here is the field:
<%= f.hidden_field :challenge_id, :value => #challenge.id %>
It successfully passes the challenge id as a param when an idea is created to the Idea Controller#create method:
Started POST "/ideas.js" for ::1 at 2015-06-18 15:39:49 -0400
Processing by IdeasController#create as JS
Parameters: {"utf8"=>"✓", "idea"=>{"title"=>"adsf", "description"=>"asf", "domain_tokens"=>"20", "challenge_id"=>"5"}, "commit"=>"Create Idea"}
This challenge_id => 5 should then be saved to the idea in the line #idea = Idea.new(idea_params) below:
ideas_controller.rb
def create
#idea = Idea.new(idea_params)
respond_to do |format|
if #idea.save
idea_count = #idea.user.ideas_created_count
#idea.user.update(:ideas_created_count => idea_count + 1)
#idea.domains.each do |domain|
current_user.add_points(1, category: domain.title)
end
#ideas = current_user.current_team.ideas.sort_by{|i| i.heat_index}.reverse
#ideas = #ideas.paginate(:page => params[:ideas_page], :per_page => 10)
format.html { redirect_to :back, notice: 'Idea was successfully created.' }
format.json { render :show, status: :created, location: #idea }
format.js
else
format.html { redirect_to :back, notice: "You must attach domains to your Idea." }
format.json { render json: #idea.errors, status: :unprocessable_entity }
format.js { render :create_failed }
end
end
end
.
.
def idea_params
params.require(:idea).permit(:title, :description, :challenge_id)
end
However, this challenge id isn't being saved to the idea with the other permitted idea_params, :title and :description. How can I get challenge_id to be saved to the Idea when it's created?
Instead of using hidden field, why not pass in the challenge_id in your form? Otherwise, you leave open the possibility that users can enter whatever they want in that hidden field.
Form:
form_for [#challenge, Idea.new] do |f|
And then:
def create
#challenge = Challenge.find(params[:challenge_id])
#idea = Idea.new(idea_params)
#idea.challenge_id = #challenge.id
end
I'm assuming you have challenge_id column in ideas table.
Try something like:
def create
#idea = Idea.new(idea_params)
#idea.challenge_id = params[:idea][:challenge_id]
#...
end
If you params or column you want to save it to is different, make sure to make the change, but you get the idea.

No route matches [PATCH] "/admin/roles.4"

I made model Role with rolify gem.
But controller made to namespace :admin :
class Admin::RolesController < ApplicationController
def index
#roles = Role.all
end
def new
#role = Role.new
end
def create
#role = Role.new(role_params)
respond_to do |format|
if #role.save
format.html { redirect_to admin_role_path(#role), notice: 'Роль создана.' }
format.json { render action: 'show', status: :created, location: #role }
else
format.html { render action: 'new' }
format.json { render json: #role.errors, status: :unprocessable_entity }
end
end
end
def show
#role = Role.find(params[:id])
end
def edit
#role = Role.find(params[:id])
end
def update
respond_to do |format|
if #role.update(role_params)
format.html { redirect_to admin_role_path(#role), notice: 'Роль обновлена.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #role.errors, status: :unprocessable_entity }
end
end
end
def destroy
#role = Role.find(params[:id])
#role.destroy
respond_to do |format|
format.html { redirect_to admin_roles_url }
format.json { head :no_content }
end
end
private
def set_role
#role = Role.find(params[:id])
end
def role_params
params.require(:role).permit(:name)
end
end
When I want to update Role, I open form, edit, click submit and get error:
Routing Error
No route matches [PATCH] "/admin/roles.4"
Please help me.
Based on the form code you pasted above, you'll see that url is pointing to the path used for creates but not updates.
You should be able to update your call to simple_form like so:
= simple_form_for [:admin, #role], :html => { :class => 'form-horizontal' } do |f|
You'll see that you can pass an array with symbolized namespace names and the object instance, and it'll build the URL correctly for both POSTs and PATCHes.
Problem is solved.
In _form I fix url.
= simple_form_for #role, url: admin_role_path(#role), :html => { :class => 'form-horizontal' } do |f|

Ruby on Rails - Passing Parameters between methods

Routes File:
resources :tournaments do
resources :game, :only => [:new, :index, :create, :update, :destroy]
end
Rake Routes shows:
new_tournament_game GET /tournaments/:tournament_id/game/new(.:format) game#new
I call:
<td><%= link_to 'Add Game', new_tournament_game_path(tournament) %></td>
Game Model:
Takes me to the view game view with the URL:
http:// local host:3000/tournaments/2/game/new
And view:
<h1>New Game in <%= #tournament.name %> Tournament</h1>
<fieldset>
<%= form_for [:tournament, #game], :url => tournament_game_index_path do |f| %>
<table>
<td>
.... More fields .....
</td>
<div class="form-actions">
<%= f.submit "Create %>
</div>
<% end %>
When create is clicked it yields the error:
undefined method `game_url' for #<GamesController:0xb6131e40>
Questions:
Should I be using nested routes or hidden fields?
Do I need a separate tournament_game controller / view to handle the tournament game calls?
How do I get it to look for the correct create route when clicking the Create button?
When I want to have a relationship between two tables, do I only need the nested resource and the has_many / belongs_to calls or do I still need a foreign key column such as Tournament?
Sorry for all of the questions in one thread. Any help you can offer would be greatly appreciated!
Thank you.
Edit:
The error references line 39 which would be the line for the create controller.
class GamesController < ApplicationController
# GET /game
# GET /game.json
def index
#game = Game.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #game }
end
end
# GET /game/1
# GET /game/1.json
def show
#game = Game.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #game }
end
end
# GET /game/new
# GET /game/new.json
def new
#game = Game.new
#tournament = Tournament.find(params[:tournament_id])
end
# GET /game/1/edit
def edit
#game = Game.find(params[:id])
end
# POST /game
# POST /game.json
def create
#tournament = Tournament.find(params[:tournament_id])
#game = #tournament.game.build(params[:game])
respond_to do |format|
if params[:commit] != 'Cancel'
if #game.save
format.html { redirect_to #game, notice: 'Game was successfully created.' }
format.json { render json: #game, status: :created, location: #game }
format.json { render json: #game }
else
format.html { render action: "new" }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
else
format.html { redirect_to #game, alert: 'Game was not updated.' }
end
end
end
# PUT /game/1
# PUT /game/1.json
def update
#game = Game.find(params[:id])
respond_to do |format|
if params[:commit] != 'Cancel'
if #game.update_attributes(params[:game])
format.html { redirect_to #game, notice: 'Game was successfully updated.' }
format.json { render json: #game }
else
format.html { render action: "edit" }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
else
format.html { redirect_to #game, alert: 'Game was not updated.' }
end
end
end
# DELETE /game/1
# DELETE /game/1.json
def destroy
#game = Game.find(params[:id])
#game.destroy
respond_to do |format|
format.html { redirect_to game_url }
format.json { head :no_content }
end
end
end
Try this:
<%= form_for #game, :url => tournament_games_path(#tournament) do |f| %>
This will call the create method of games controller
Game Controller:
def create
#tournament = Tournament.find(params[:tournament_id])
#game = #tournament.games.build(params[:game])
if #game.save
flash[:success] = "Game created successfully"
redirect_to tournaments_path
else
render new_tournament_game_path
end
end
Routes:
resources :tournaments do
resources :games, :only => [:new, :index, :create, :update, :destroy]
end

create new devise user from another non devise controller

I have a users table (Devise) , with a column "admin" (boolean) to qualify my users.
I also have a namespace "Backend".
I would like that my admins users can create new users from the backend namespace.
So I created a Backend::UsersController :
class Backend::UsersController < ApplicationController
layout 'admin'
before_filter :authenticate_user!
def index
#auteurs = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #auteurs }
end
end
def new
#auteur = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #auteur }
end
end
def create
#auteur = User.new(params[:auteur])
respond_to do |format|
if #auteur.save
format.html { redirect_to #auteur, notice: 'Article was successfully created.' }
format.json { render json: #auteur, status: :created, location: #auteur }
else
format.html { render action: "new" }
format.json { render json: #auteur.errors, status: :unprocessable_entity }
end
end
end
end
Here's the "_form" partial called in the "new" view :
<%= simple_form_for(#auteur) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :email %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
An here's my routes :
namespace :backend do
resources :articles
root to: "articles#index"
resources :accueil
resources :users
get "users/index"
get "users/create"
get "users/new"
end
devise_for :users
But when I try to access to "backend/users/new", it drives me to this error :
NoMethodError in Backend/users#new
Showing C:/Ruby/acturevue/app/views/backend/users/_form.html.erb where line #1 raised:
undefined method `users_path' for #<#<Class:0x39616b0>:0x416f6d0>
Does somebody have any ideas of the source of the problem ?
Thanks
UPDATE
So, I modified my code like that :
In Backend::UsersController :
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user}
end
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to backend_users_path(#user), notice: 'Article was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
In _form :
<%= simple_form_for(#user) do |f| %>
But I still have the error.
However the backend_users_path exists in y routes :
backend_users GET /backend/users(.:format) backend/users#
index
POST /backend/users(.:format) backend/users#
create
new_backend_user GET /backend/users/new(.:format) backend/users#
new
edit_backend_user GET /backend/users/:id/edit(.:format) backend/users#
edit
backend_user GET /backend/users/:id(.:format) backend/users#
show
PUT /backend/users/:id(.:format) backend/users#
update
DELETE /backend/users/:id(.:format) backend/users#
destroy
You need to use the namespace in your redirect:
redirect_to [:backend, #auteur] #...
See my answer to this question.

Rails: form with :url specified can't be used as partial?

Hi I'm trying to use a form as a partial for both the new/edit views of my albums controller/model. However, it's giving me the error when I try to edit the album:
No route matches [PUT] "/users/22/albums"
I think this might have to do with my form's :url. My form works fine when I submit it to create an album, but gets that error when I try to edit it.
I tried taking out the url: user_albums_path in my form, but it would just give me an error when I try to create a new album.
No route matches [POST] "/albums"
Is there any way to make it so that the form works for both actions? I feel like the :url can't coexist properly in both actions.
_form.html.erb
<%= form_for (#album), url: user_albums_path, :html => { :id => "uploadform", :multipart => true } do |f| %>
<div class="formholder">
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_area :description %>
<br>
<%=f.submit %>
</div>
<% end %>
albums controller
class AlbumsController < ApplicationController
def index
#user = User.find(params[:user_id])
#albums = #user.albums.all
respond_to do |format|
format.html
format.json { render json: #albums }
end
end
def show
#user = User.find(params[:user_id])
#album = #user.albums.find(params[:id])
end
def update
#user = User.find(params[:user_id])
#album = #user.albums.find(params[:id])
respond_to do |format|
if #album.update_attributes(params[:album])
format.html { redirect_to user_album_path(#user, #album), notice: 'Album successfully updated' }
else
format.html { render 'edit' }
end
end
end
def edit
#user = User.find(params[:user_id])
#album = #user.albums.find(params[:id])
end
def create
#user = User.find(params[:user_id])
#album = #user.albums.build(params[:album])
respond_to do |format|
if #user.save
format.html { redirect_to user_album_path(#user, #album), notice: 'Album was successfully created.' }
format.json { render json: #album, status: :created, location: #album}
else
format.html { render action: "new" }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
def new
#user = User.find(params[:user_id])
#album = Album.new
end
def destroy
end
end
please help!
update:
FIXED IT! on my own! the form just needed to be <%= form_for([#user, #album])...
Try
<%= form_for [#user, #album] %>
# other arguments can be inserted before the closing brace
That syntax properly scopes the resource routes
Remember to have an #album instance variable if you need one. You can build an empty album using #user.album.build

Resources