Cannot create new object in rails - ruby-on-rails

I am trying to create a basic Item creation in rails but I am having trouble creating new item. I want to create item's name, say Wash the dishes. These are the codes that I have:
Routes:
resources :items
ItemsController:
class ItemsController < ApplicationController
...
def new
#item = Item.new
end
def create
#item = Item.new(item_params)
if #item.save
flash[:notice] = "Item was saved!"
redirect_to #item
else
flash.now[:alert] = "ERROR. ERROR."
render :new
end
end
...
private
def item_params
params.require(:item).permit(:name, :list_id)
end
end
items/new.html.erb
<%= form_for :item do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
Lastly, schema:
create_table "items", force: :cascade do |t|
t.string "name"
t.integer "list_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
...
I got several different error codes, but this is the one I am currently stuck at (other times it showed different error code or it would simply prints out "ERROR. ERROR." (alert that I setup when save fails)
Routing Error
No route matches [POST] "/items/new"
When I go to rake routes:
POST /items(.:format) items#create
new_item GET /items/new(.:format) items#new
I followed suggestion from this SO post to check my routes and this is what I have:
2.2.2 :019 > r = Rails.application.routes
=> #<ActionDispatch::Routing::RouteSet:0x007fff323c3230>
2.2.2 :020 > r.recognize_path "/items/new"
=> {:controller=>"items", :action=>"new"}
I have also gone to rails c and I was able to create new item manually. (i = Item.new(name:"Test 123"); i.save)
What did I miss?

The problem is with your form. To understand what's wrong, do the following:
Start the rails server using rails s
Go to http://localhost:3000/items/new
Instead of filling in the form fields, view the source page
Check the form tag. Its submitting the form data to /items/new. ie.the action attribute is set to /items/new. Why is that?
From the documentation:
When the model is represented by a string or symbol, if the :url option is not specified, by default the form will be sent back to the current url (We will describe below an alternative resource-oriented usage of form_for in which the URL does not need to be specified explicitly).
<form action="/items/new" accept-charset="UTF-8" method="post">
In your routes.rb, there's no route matching POST /items/new
So, modify your form to
<%= form_for :item, url: items_path do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
This generates a form tag which posts the data to /itemsrather than /items/new.
Or replace your form with
<%= form_for #item do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
Now, the form will be submitted to /items. The advantage of using the second version is you can dry out your form for creating a new object and updating an existing object into a single view(partial).
For more, see http://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object

Try this in items/new.html.erb
<%= form_for #item do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>

Related

Ruby - Saving a Model shows a Get url in browser

Ruby 2.2.4
Rails 4.2.6
PostgreSQL 9.5
I am trying to save a simple model, but when I submit the form, my browser url shows this "http://localhost:8080/notes/new?utf8=%E2%9C%93&authenticity_token=z0cyVNfUKYWDSDASDWFFZ96zj29UTtDYe8dLlKrI6Mbznb2SrTWNm%2BQ91D2s2AASD2345Fl3fTOneCC2dNg%3D%3D&note%5Btitulo%5D=ddddddd&note%5Bconteudo%5D=dddddddddddddddddd&commit=Create"
I am curious about this because other project, it has the same methods, same routes, the only difference is the model that only have one column, but it works fine.
def change
create_table :notes do |t|
t.text :titulo
t.text :conteudo
t.timestamps null: false
end
My controller: notes_controller.rb
def new
#note = Note.new
end
def create
#note = Note.new(note_params)
if #note.save
redirect_to '/'
else
render 'new'
end
end
private
def note_params
params.require(:note).permit(:titulo,:conteudo)
end
my form
<%= form_for(#note) do |f| %>
<div class="field">
<%= f.label :titulo %><br>
<%= f.text_area :titulo %>
<%= f.label :conteudo %><br>
<%= f.text_area :conteudo %>
</div>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
my routes
Rails.application.routes.draw do
root 'notes#index'
get 'notes/new' => 'notes#new'
post 'notes' => 'notes#create'
I saw this post Rails form issuing GET request instead of POST request
but does not work for me.
Edit:
I fix it thanks to Anthony E, his answer made me look back to code and realize that I have a form inside a form. The outer form was in application.html.erb.
Thanks to all.
Rails can't infer the appropriate form route from your model. Try explicitly setting the form URL and submit method in your form_for:
form_for #note, url: "/notes", as: :note, html: { method: :post } do |f|
end
Alternatively, it may be simpler to use resourceful routing:
In routes.rb:
resources :notes, only: [:new, :create, :index]
This will create the following routes:
GET /notes/new # Maps to NotesController#new
POST /notes # Maps to NotesController#create
GET /notes # Maps to NotesController#index

Ruby on Rails - NoMethodError in Signups#new

I'm getting this error while trying to pass "Innovation Cloud" lesson on Codecademy. I couldn't find any solution on Stack Overlow or GitHub.
NoMethodError in Signups#new
Showing /home/ccuser/workspace/learn-rails_innovation-cloud/innovation-cloud/app/views/signups/new.html.erb where line #40 raised:
undefined method `email' for #<Signup id: nil, created_at: nil, updated_at: nil>
Important fragments of code:
routes.rb:
Rails.application.routes.draw do
get "/thanks" => "pages#thanks"
resources :signups
root "signups#new"
end
new.html.erb
<%= form_for(#signup) do |f| %>
<div class="field">
<%= f.label :signup %><br>
<%= f.text_area :email %>
</div>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
db/migration
class CreateSignups < ActiveRecord::Migration
def change
create_table :signups do |t|
t.string :email
t.timestamps
end
end
end
signups_controller.rb
class SignupsController < ApplicationController
def new
#signup = Signup.new
end
private
def signup_params
params.require(:signup).permit(:email)
end
def create
#signup = Signup.new(signup_params)
if #signup.save
redirect_to '/thanks'
else
render 'new'
end
end
end
As the error implies, some code tried to call a method email on an instance of Signup. Its not clear what line of code corresponds to the line number 40, but my guess is its the following:
<%= f.text_area :email %>
Anytime you build a form with an ActiveRecord instance (as you do with form_for(#signup)), any input generated will expect an attribute on your model with the same name. In this case, its looking for an attribute named email on #signup. It does this so that the field can be populated with the current value of that attribute on the model. While this might seem unnecessary for a #new action, it makes perfect sense for an #edit action, and allows you to reuse the same form code for both.
Since I'm guessing you'd like to store the email along with the signup, you need to add the attributes to the Signup model with a migration like so:
rails generate migration AddEmailToSignup email:string
rake db:migrate

Integrating user id into creation of a new object in an Activerecord database

Creating a simple flashcard app with a single has many, belongs to relationship:
card belongs_to :user
user has_many :cards
Because of AR conventions, have set up a validation for user_id in the cards table to reflect the association:
create_table "cards", force: :cascade do |t|
t.string "word_text", null: false
t.string "meaning_text", null: false
t.integer "user_id", null: false
end
Now, running feature tests on the creation of a new flashcard, running into trouble because i don't know how to ensure that the user_id column in the newly created object gets filled in with user.id... tried adding this to my form, but nothing seems to work...
```
<%= form_for #card do |f| %>
<%= f.label :word_text %>
<%= f.text_field :word_text %>
<%= f.label :meaning_text %>
<%= f.text_field :meaning_text %>
<%= f.label :user_id %>
<%= f.number_field :user_id %>
<%= f.submit "Create" %>
```
I know that this is the error because when I enter #card.save! in rails console i get this error:
ActiveRecord::RecordInvalid: Validation failed: User can't be blank
If I'm signed in okay, should the user id be automatically used to create the new object?
Very new to rails and can't seem to decipher what's going on here. Any help would be much appreciated. Thanks!
You probably have a create action like this in your CardsController:
def create
card = Card.new(card_params)
if card.save
redirect_to some_path
else
redirect_to some_other_path
end
end
You should append the user's id in this create action and not ask (neither add a hidden_field as suggested) for the user's id in the form.
def create
card = Card.new(card_params.merge(user_id: current_user.id))
if card.save
redirect_to some_path
else
redirect_to some_other_path
end
end

No route matches [POST] "/companyrating/index"

I am newbie to ruby on rails. I am getting this error. I have followed this tutorial http://www.codelearn.org/ruby-on-rails-tutorial/forms-form_tag-params-attr_accessible-model-validation
for the form posting. But when I click on submit i was getting an error
this is my
controller
class CompanyratingController < ApplicationController
def index
#companies = Companyrating.all
end
def add
#companies.create(:companies => params[:name, :place, :rate, :rank])
#redirect_to :action => 'index'
#companies = Companyrating.new(params[:name])
if #companies.save
flash[:success] = "Welcome to My Space!"
redirect_to root_url
end
end
end
this is modal
class Companyrating < ActiveRecord::Base
attr_accessible :name, :place, :rate, :rank
end
this is my routes file
get "companyrating/index"
match "companyrating/add" => "todos#add", :via => :post
my index file
<title>Shared Todo App </title>
<h1>Shared Todo App</h1>
<p>All your todos here</p>
<ul><li> <% #companies.each do |t| %>
<li> <%= t.companies_name %> </li>
<li> <%= t.companies_place %> </li>
<li> <%= t.companies_rate%> </li>
<li> <%= t.companies_rank %> </li>
<% end %>
</li></ul>
<%= form_for("#companies/add", :method=>"post") do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :place %>
<%= f.text_field :place %>
<%= f.label :rate %>
<%= f.text_field :rate %>
<%= f.label :rank %>
<%= f.text_field :rank %>
<%= f.label :user_id%>
<%= f.text_field :user_id %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
This was my error: No route matches [POST] "/companyrating/index"
can anyone help me in solving this error
in controller:
def new
#companyrating = Companyrating.new
end
def create
#companies = Companyrating.new(params[:companyrating])
if #companies.save
flash[:success] = "Welcome to My Space!"
redirect_to root_url
else
flash[:error] = "Can't create companyrating."
render 'new'
end
end
in routes.rb:
resources :companyrating
in form:
<%= form_for(#companyrating, method: :post) do |f| %>
The problem you're having is two-fold - with your routes and controller actions
I know Monk_Code gave an answer, but since you're new, I'll explain how it all works for you, with the goal of helping you understand the system a bit better:
Routes
Your first issue is to do with your routes
Rails has done an amazing job of creating great routing structures, and the core of this is the idea of resourceful routes
By using the following code, your Rails app creates a series of 7 routes which Rails uses to send "default" traffic to your controller actions:
#config/routes.rb
resources :companyratings
This routing structure creates the following routes in your app:
new [GET]
index [GET]
create [POST]
edit [GET]
update [POST]
destroy [DELETE]
show [GET]
All of these routes take directed traffic, and routes it to the relevant controller action. This means that if you send a user to /companyratings/, it's going to load the index action, likewise /companyratings/15 will show the show action in the controller
On top of this, you also need to know what the HTTP "verb" does. This is a key principle which Rails uses to route your traffic accordingly. The "verb" in your request is the type of request that's sent, and is dependent on the browser
As you can see from the list above, every route has an associated HTTP verb. The reason why this is important is because if you send a [GET] request to a route which only works with the [DELETE] verb, you're going to get a problem, hence why you're seeing errors when you send a [POST] request to your index action
You should read the Rails tutorial on this, as you can either fix the issue by sending the correct HTTP verb (using :method => :get), or specify the [POST] verb in your index action route
Controller Actions
Controller actions are the function defined in your controller, which are loaded when you run a particular request in Rails
The default index actions are listed above, but you can also have any others you like, as long as you provide the correct routes. Your problem is that you've just used the add action, where you should have used the create action:
class CompanyratingController < ApplicationController
def index
#companies = Companyrating.all
end
def new
#companyrating = Companyrating.new
end
def create
#companies = Companyrating.new(new_company_rating)
if #companies.save
flash[:success] = "Welcome to My Space!"
redirect_to root_url
end
end
private
def new_company_rating
params.require(:company_rating).permit(:variables, :listed, :here)
end
end

is an instance variable in an action of a controller available for all the controllers view?

I am just trying to print the parameters that have been entered into my form.
Basically I create a new bet then I display the parameters:
MIGRATION
class CreateBets < ActiveRecord::Migration
def self.up
create_table :bets do |t|
t.integer :accepted ,:default => 0
t.integer :user_1_id #proposer
t.integer :user_2_id #receiver
t.integer :team_1_id #proposer's team
t.integer :team_2_id #receiver's team
t.integer :game_id
t.integer :winner
t.integer :amount
t.timestamps
end
end
def self.down
drop_table :bets
end
end
CONTROLLER
bets_controller.erb
class BetsController < ApplicationController
def index
redirect_to new_bet_path
end
def new
#b=Bet.new
end
def create
#points=params[:points]
#winner=params[:winner]
end
end
VIEWS
New.erb
<% facebook_form_for Bet.new do |f| %>
<%= f.text_field :amount, :label=>"points" %>
<%= f.text_field :winner, :label=>"WinningTeam" %>
<%= f.buttons "Bet" %>
<% end %>
create.erb
points:<%= #points %>
<br>
winner:<%= #winner %>
I tried to make this code work with instance variables but it didn't work either. Where is the problem?
Thank you.
I think that params[:winner] and params[:point] is empty hash. Try adding this to your create.erb:
params: <%= params.inspect %>
It will display your params hash, so you will see how to get to it.
Another hint, why you are creating new object in new action and then in form you are doing it again? So:
<% facebook_form_for #b do |f| %>
And another thing, it is really good to keep naming conventions, so don't create #b object, but #bet.
In create action you should have line like this:
#bet = Bet.new(params[:bet])
And in view:
<p>
points:<%= #bet.points %>
</p>
<p>
winner:<%= #bet.winner %>
</p>
If you use <br> it's better to use <br/>.
Your index action is totaly useless. It would be better if you would move all behaviour from new action to index and remove new action completly.
As klew pointed, for me it seems that you're getting empty params[:winner]and params[:point]. You can make sure that of what you're getting by taking a look at your servers log.
You will see a line like
Processing BetsController#create (for 127.0.0.1 at 2010-04-11 20:56:51) [POST]
Parameters: {"your"=>"parameters", "should"=>"apper in this hash"}

Resources