Ruby on Rails - No data in Params to save in database - mysql

My problem is similar to this question: Ruby on Rails - Data not saved. Index showing blank values
However the strong params match the answers and no data seems to come through.
If I use params.require(:banktransaction).permit(...) I get an error: param is missing or the value is empty
If i remove the require part, a row is added but with no values.
I went through the view and controller and checked my spelling, for the life of me I can't see what I have missed, can anyone point me in the right direction?
controller:
class BankAccountsController < ApplicationController
def delete
end
def destroy
end
def edit
end
def update
end
def index
#bankaccount = BankAccount.all
end
def show
end
def new
#banktransaction = BankAccount.new(:transactionDate => Time.now, :description => params[:description], :credit => params[:credit], :debit => params[:debit])
end
def create
#banktransaction = BankAccount.new(bank_account_params)
if #banktransaction.save
flash[:notice] = "transaction added successfully."
redirect_to(bank_accounts_path)
else
render('new')
end
end
private
def bank_account_params
params.require(:banktransaction).permit(:transactionDate,:description,:credit,:debit)
end
end
View:
<h1>BankAccounts#new</h1>
<p>Find me in app/views/bank_accounts/new.html.erb</p>
<div class="new transaction">
<h2>Create Transaction</h2>
<%= form_for(#banktransaction, :html => {:multipart =>true }) do |f| %>
<%= render(:partial =>'form', :locals=> {:f => f}) %>
<div class="form-buttons">
<%= f.submit("Create Transaction") %>
</div>
<% end %>
</div>
Form partial:
<%= f.label(:transactionDate) %>: <%= f.date_field(:transactionDate) %><br>
<%= f.label(:description) %>: <%= f.text_field(:description) %><br>
<%= f.label(:credit) %>: <%= f.number_field(:credit) %><br>
<%= f.label(:debit) %>: <%= f.number_field(:debit) %><br>
routes:
Rails.application.routes.draw do
resources :bank_accounts do
member do
get :delete
end
end
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

In short, you just permit wrong params key. It's bank_account and your bank_account_params should be
def bank_account_params
params.require(:bank_account).permit(:transactionDate,:description,:credit,:debit)
end
The Rails's form builder will build your params base on model name, not variable name.
Your new action assign a BankAccount instance
def new
#banktransaction = BankAccount.new(:transactionDate => Time.now, :description => params[:description], :credit => params[:credit], :debit => params[:debit])
end
so the form builder will use bank_account as the param key instead of variable name banktransaction

Related

Rails - Save client model into the database

Hey here! I'm kinda new to Rails and I've been trying to find some answers but no luck yet so here we go.
I've set up a basic Rails app and just trying to save a Client to my database with a validation but nothing seems to be coming together. Anyone could point me to the right direction please or let me know what I've been doing wrong in my code.
I keep getting errors like this:
NoMethodError in Clients#new
Showing /Users/******/Documents/******/*****/app/views/clients/_form.html.erb where line #1 raised:
undefined method `clients_path' for #<ActionView::Base:0x00000000064a50>
Did you mean? clients_new_path
Even if I remove #client = Client.new from the new method I can view the page but nothing gets saved.
I'm stuck really now so any help much appreciated!
Thanks!
My Routes.rb file:
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
get 'dashboard/index'
root to: "home#index"
devise_for :users, controllers: {
sessions: 'users/sessions',
passwords: 'users/passwords',
registrations: 'users/registrations'
}
get '/clients/index'
get '/clients/new'
get '/clients/edit'
get '/clients/delete'
get '/clients/:id', to: 'clients#show'
post '/clients/new', to: 'clients#create'
end
My Dashboard file:
<% if user_signed_in? %>
<nav class="subnav">
<ul>
<li><%= link_to('My Clients', clients_index_path) %></li>
<li><%= link_to('Add Client', clients_new_path) %></li>
<li><%= link_to('Edit registration', edit_user_registration_path) %></li>
<li><%= link_to('Logout', destroy_user_session_path, :method => :delete) %></li>
</ul>
</nav>
<% else %>
<%= link_to('Register', new_user_registration_path) %>
<%= link_to('Login', new_user_session_path) %>
<% end %>
My ClientsController file:
class ClientsController < ApplicationController
def index
#clients = Client.all
end
def new
#client = Client.new
end
def show
#client = Client.find(params[:id])
end
def create
#client = Client.new(client_params)
if #client.save
redirect_to #client
else
render :new
end
end
def edit
end
def delete
end
private
def client_params
params.require(:client).permit(:name, :provider)
end
end
My form:
<%= form_with model: #client do |form| %>
<div>
<%= form.label :name %><br>
<%= form.text_field :name %>
<% client.errors.full_messages_for(:name).each do |message| %>
<div><%= message %></div>
<% end %>
</div>
<div>
<%= form.label :provider %><br>
<%= form.text_field :provider %>
</div>
<div>
<%= form.label :business_type %><br>
<%= form.select :business_type, ["Partnership", "Sole Trader", "Limited Company"] %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
Finally my new.html.erb file:
<h1>Clients#new</h1>
<%= render 'form', client: #client %>
clients_path is generated by resources :clients, only: :index or you probably need to give your route the name you want. Try this
get '/clients/index', as: :clients
or, if you want to specify non default paths as you're doing, your index is probably called clients_index_path, but you can check that with a rake routes or rails routes, because I'm not sure.
That said, I suggest you to go with the resources method in your routes file and use the default paths as you're trying to do. Something like
resources :clients
but now you don't have a path like /clients/index no more, just /clients for the index action.
If you're in doubts with routes try to read the guide about routing
The Rails way to declare the routes to Create, Update, Read and Destroy (CRUD) a resource is just:
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
get 'dashboard/index'
root to: "home#index"
devise_for :users, controllers: {
sessions: 'users/sessions',
passwords: 'users/passwords',
registrations: 'users/registrations'
}
resources :clients
end
As you can see by the annotions above each method Rails does not add the "action" to the path except for the new and edit routes:
class ClientsController < ApplicationController
before_action :set_client, only: [:show, :edit, :update, :destroy]
# GET /clients
def index
#clients = Client.all
end
# GET /clients/1
def show
end
# GET /clients/new
def new
#client = Client.new
end
# POST /clients
def create
#client = Client.new(client_params)
if #client.save
redirect_to #client
else
render :new
end
end
# GET /clients/edit
def edit
end
# PATCH /clients/1
def update
if #client.update(client_params)
redirect_to #client
else
render :edit
end
end
# DELETE /clients/1
def delete
#client.destroy
redirect_to action: :index,
notice: 'Client deleted'
end
private
def set_client
#client = Client.find(params[:id])
end
def client_params
params.require(:client).permit(:name, :provider)
end
end
Thus you don't create resources with post '/clients/new' - You use POST /clients. Also when you use the "bare-bones" routing methods such as match, get, post etc Rails does not automatically add routing helper. If you actually wanted to generate the equivilent routes you would need to use:
post '/clients',
to: 'clients#create',
as: :clients
But you're much better off embracing the conventions and learning to use them to be productive.

Multiple radio buttons getting selected in Rails app

I have an app where Question model has_many relationship with Option. I also have a button to add options while creating a question. Every question has only one correct answer. So when I create a question and click on Add Option button, new option is created but the new radio button associated with it has different name. In fact the name of radio button is of the form question[options_attributes][i][is_answer] where i is id. As far as I know radio buttons should have the same name to work as a collection or group. So how can I make it work as a group even if I create any number of options for a single question?
html.erb
<%= form_for #question do |form| %>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<%= form.fields_for :options, question.options.each do |a| %>
<div class="field">
<%= a.label :options %>
<%= a.text_area :body %>
<%= a.radio_button :is_answer, "options" %>
<%= a.check_box :_destroy %>
<%= a.label :_destroy, 'delete' %>
</div>
<% end %>
<%= form.submit 'Add option', :name => "add_option" %>
<%= form.submit 'Delete options', :name => "remove_option" %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
controller.rb
class QuestionsController < ApplicationController
def new
#question = Question.new
#question.options.build
end
def create
#question = Question.new(question_params)
#question.user = current_user
if params[:add_option]
#question.options.build
else
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' and return }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
render :action => 'new'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:body, options_attributes: [:id, :body, :question_id, :created_at, :updated_at, :is_answer])
end
end
There are two options:
Using JavaScript on the client-side to uncheck the radio buttons.
Using radio buttons with the same name. It this case you will have to change the way you pass the :is_answer parameter and manually assign the value in options_attributes.
Method 1 details:
See this question radio different names - only check one
Method 2 details:
Instead of passing :is_answer parameter for each option you can pass a single parameter for the question having chosen answer id as the value. Lets name it "answer_id". We want this parameter to be in the params[question]
hash in the controller, so the whole name will be "question[answer_id]". Although radio buttons are generated for each option, only the chosen one will be sent to the server as they all have the same name.
<%= form.fields_for :options, question.options.each do |a| %>
<div class="field">
<%= a.label :options %>
<%= a.text_area :body %>
<%= radio_button_tag "question[answer_id]", a.object.id, a.object.is_answer? %>
<%= a.check_box :_destroy %>
<%= a.label :_destroy, 'delete' %>
</div>
<% end %>
https://apidock.com/rails/v4.2.7/ActionView/Helpers/FormTagHelper/radio_button_tag
In the controller you will have to manually assign the option's is_answer parameter based on the answer_id value.
def question_params
result = params.require(:question).permit(:body, :answer_id, options_attributes: [:id, :body, :question_id])
answer_id = result.delete(:answer_id)
result[:options_attributes].values.each do |option_attrs|
option_attrs[:is_answer] = option_attrs[:question_id] == answer_id
end
result
end
If you need further details please let me know. I will update the answer to give more information.

Pass values from select_tag in params

I created a "select_tag" field and I need it when the user clicks save all the values of this field to be passed by params to the controller. The problem is that when I click save, only the first value entered in this field is passed to the controller.
To better understand, the "select_tag" field is populated through another field, the "f.text_field :members" field. When I click on an "add" button the value of the "f.text_field :members" field is passed to the "select_tag" field and so I want to be able to check all these values from the "select_tag" field to validate and save, how do I do that? As I already said, only the first value entered is passed.
Looking at the params now, I realized that the value that returns as "params" is just the value that is selected in the dropdown, the other values are not considered. How do I pass all values in the dropdown?
Code:
<%= form_for(#focus_group) do |f| %>
<% if #focus_group.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#focus_group.errors.count, "error") %> prohibited this focus_group from being saved:</h2>
<ul>
<% #focus_group.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<script type="text/javascript">
$(function() {
$('#focus_group_moderator, #focus_group_members').autocomplete({
source: '/focus_groups/autocomplete.json'
});
});
function add(){
var value = $('#focus_group_members').val();
var select = document.getElementById("membersAdded");
var option = document.createElement("option");
option.text = value;
option.value = value;
select.add(option);
$('#focus_group_members').val("");
}
function removeFromSelect(){
var select = document.getElementById("membersAdded");
select.remove(select.selectedIndex);
}
</script>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :topic %><br>
<%= f.text_field :topic %>
</div>
<div class="field">
<%= f.label :moderator %><br>
<%= f.text_field :moderator %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :members %><br>
<%= f.text_field :members %>
<input onclick="add()" type="button" value="Add" /><br>
<%= select_tag(:membersAdded, options_for_select([])) %>
<input onclick="removeFromSelect()" type="button" value="Remove" /><br>
<br>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
CONTROLLER
class FocusGroupsController < ApplicationController
before_action :set_focus_group, only: [:show, :edit, :update, :destroy]
include FocusGroupsHelper
def index
if(params[:term])
#profile = Profile.all.select("name", "id")
#lista = Array.new
#profile.each do |x|
#lista.push(x.name)
end
respond_to do |format|
format.html
format.json { render json: #lista.to_json}
end
else
#focus_groups = FocusGroup.all
end
end
def show
end
def new
#focus_group = FocusGroup.new
#membersAdded
respond_to do |format|
format.html
format.json { render json: Profile.all.to_json}
end
end
def edit
end
def create
#moderator= find_profiles_id(focus_group_params[:moderator])
#moderator.each do |f|
#moderator_id = f.id
end
#params = focus_group_params
#params[:moderator] = #moderator_id
#focus_group = FocusGroup.new(#params)
if #focus_group.save
redirect_to #focus_group, notice: 'Focus group was successfully created.'
else
render :new
end
end
def update
if #focus_group.update(focus_group_params)
redirect_to #focus_group, notice: 'Focus group was successfully updated.'
else
render :edit
end
end
def destroy
#focus_group.destroy
redirect_to focus_groups_url, notice: 'Focus group was successfully destroyed.'
end
def autocomplete
if(params[:term])
#profile = Profile.all.where("user_id <> 0 and is_template = 'f' and name LIKE ?", "#{params[:term]}%").select("name", "id")
#lista = Array.new
#profile.each do |x|
#lista.push(x.name)
end
respond_to do |format|
format.html
format.json { render json: #lista.to_json}
end
end
end
def find_profiles_id(name)
return Profile.all.where("name LIKE ?", "#{name}%").select("id")
end
def find_profiles_name(id)
#profile = Profile.all.where("id = ?", "#{id}").select("name")
#profile.each do |e|
#name = e.name
end
return #name
end
private
def set_focus_group
#focus_group = FocusGroup.find(params[:id])
end
def focus_group_params
params.require(:focus_group).permit(:name, :topic, :moderator, :description, :members, :membersAdded)
end
end
Several ways to approach this -- but the select box itself doesn't make any sense to use in this situation. Provides no utility. Here's one way. Do you have a separate members model? It seems like you're essentially trying to do a nested form. If you don't have a members model, create one. Create a focus group separately and put the form for members on the FocusGroup's show page. A focus group has many members and member belongs to a focus group (has a focus group id). This will allow you to say #focus_group.members and get all the members back.
If you must add them on the same form for some reason (I don't think this is optimal), you'll want to do so via a nested form with a form builder that allows you to add many at once. You could also make a service object but that is more complicated.
Another option, which I like less, would be to push all of the members to an array and then pass it as a param on submit. Instead of adding the members to the select box you'd just push them to an array. Then you would set the final array value to members_added (or whatever you name the parameter). You'll need to unpack that array in the controller to create each member. I like this much less. The first option is the cleanest. I think this is the third best approach of the three.

Ruby on Rails - basic form submission

I have been working on PHP. Presently trying to learn Ruby on Rails. I am learning Rails online, for now I am badly stuck on Sign-up or can say a form submission page. Sorry if it's too silly.
Error is:
undefined method new for nil:NilClass
Here is the code:
users_controller.rb
class UsersController < ApplicationController
def new
#user= User.new
end
def create
#user.new(params[:user])
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
else
flash[:notice]= "failed"
flash[:color]="invalid"
end
render "new"
end
end
new.html.erb
<% page_title="Signup" %>
<div class="Sign_Form">
<h1>Sign up</h1>
<%= form_for(:user, :url => {:controller => 'users', :action => 'create'}) do |f| %>
<p> Username:</br> <%= f.text_field :username%> </p>
<p> Email:</br> <%= f.text_field :email%> </p>
<p> Password:</br> <%= f.password_field :password%></p>
<p> Password Confirmation:</br> <%= f.password_field :password_confirmation%> </p>
<%= f.submit :Signup %>
<% end %>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<% for message_error in #user.errors.full_messages %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
user.rb
class User < ActiveRecord::Base
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i
validates :username, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true #:format => EMAIL_REGEX
validates :password, `enter code here`:presence =>true #:confirmation => true #password_confirmation attr
validates_length_of :password, :in => 6..20, :on => :create
end
In your users_controller > create, you put capital letter on User param.
For your case, it should be all lower case params[:user].
Side note, it actually depends on your attribute name you set on the form in the first place.
Edit:
In addition of that you should put #user = User.new(params[:user])
First thing you should create new object of User class
Second pass correct params key
change first line in create method to
#user = User.new(params[:user])
So the changed code will look like this:
class UsersController < ApplicationController
def new
#user= User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
else
flash[:notice]= "failed"
flash[:color]="invalid"
end
render "new"
end
end
change #user.new(params[:user]) to #user = User.new(params[:user]) I creates #user but it is not saved to database yet. On the line below #user.save that is when it gets saved. And remove render new because it will render the template with out setting the variables that the template needs. instead use redirect_to :new that will send the user to new and also set the variables needed
I guess you need to allow the params of User model in the User controller so as to avoid the forbidden error message as mentioned here. Please note that this is Rails feature as mentioned
Rails has several security features that help you write secure applications, and you're running into one of them now. This one is called strong parameters, which requires us to tell Rails exactly which parameters are allowed into our controller actions.
Thanks

Unable to perform edit operation in ruby on rails

I am very new bee to ruby on rails, i have just created a small project which add,update and delete a record from mysql db
I am able to successfully add and delete record from mysql db from ruby application
But the issue is only when i try to update the existing record
My code is as follows,
Controller:
class BookController < ApplicationController
def list
#books = Book.find(:all)
end
def show
#book = Book.find(params[:id])
end
def new
#book = Book.new
#subjects = Subject.find(:all)
end
def create
#book = Book.new(params[:book])
if #book.save
redirect_to :action => 'list'
else
#subjects = Subject.find(:all)
render :action => 'new'
end
end
def edit
#book = Book.find(:all)
#subjects = Subject.find(:all)
end
def update
#book = Book.find(params[:id])
if #book.update_attributes(params[:book])
redirect_to :action => 'show', :id => #book
else
#subjects = Subject.find(:all)
render :action => 'edit'
end
end
def delete
Book.find(params[:id]).destroy
redirect_to :action => 'list'
end
def show_subjects
#subject = Subject.find(params[:id])
end
end
List HTML:
<% if #books.blank? %>
<p>There are not any books currently in the system.</p>
<% else %>
<p>These are the current books in our system</p>
<ul id="books">
<% #books.each do |c| %>
<li>
<%= link_to c.title, {:action => 'show', :id => c.id} -%>
<b><%= link_to "edit", {:action => 'edit', :id => c.id} %></b>
<b> <%= link_to "Delete", {:action => 'delete', :id => c.id},
:confirm => "Are you sure you want to delete this item?" %></b>
</li>
<% end %>
</ul>
<% end %>
<p><%= link_to "Add new Book", {:action => 'new' }%></p>
Edit HTML:
=========
<h1>Edit Book Detail</h1>
<%= form_tag(:action=> "update") do%>
<p><label for="book_title">Title</label>:
<%= text_field 'book', 'title' %></p>
<p><label for="book_price">Price</label>:
<%= text_field 'book', 'price' %></p>
<p><label for="book_subject">Subject</label>:
<%= collection_select(:book, :subject_id,
#subjects, :id, :name) %></p>
<p><label for="book_description">Description</label><br/>
<%= text_area 'book', 'description' %></p>
<%= submit_tag "Save changes" %>
<%end %>
<%= link_to 'Back', {:action => 'list' } %>
I am getting the following exception when i try to edit a record from URL http://localhost:3000/book/edit/5,
Showing C:/app/app/views/book/edit.html where line #5 raised:
undefined method `title' for #<Array:0x33315c0>
Extracted source (around line #5):
2: <%= form_tag(:action=> "update") do%>
3:
4: <p><label for="book_title">Title</label>:
5: <%= text_field 'book', 'title' %></p>
6: <p><label for="book_price">Price</label>:
7: <%= text_field 'book', 'price' %></p>
8: <p><label for="book_subject">Subject</label>:
BTW i am using rails3,ruby1.2 and mysql5.5.
As i am in a learning curve, it will be very useful if some one can help me in this issue.
For some reason you're loading all the book records when the usual intention of the edit method is to edit one of them.
To fix this, you should define a before_filter hook that handles loading records:
class BookController < ApplicationController
# Set a handler for loading the book for most actions, except those
# where loading a single book is not relevant.
before_filter :load_book, :except => [ :index, :new, :create ]
def edit
#subjects = Subject.find(:all)
end
def update
# Call the update_attributes method that will throw an exception if
# an error occurs.
#book.update_attributes!(params[:book])
redirect_to :action => 'show', :id => #book
rescue ActiveRecord::RecordInvalid
# This exception is triggered if there was an error saving the record
# because of a validation problem.
# Trigger 'edit' action
edit
# Render as if on 'edit' page
render :action => 'edit'
end
protected
def load_book
#book = Book.find(params[:id])
end
end
As a note, any time you call either find(:all) or all on a model, you run the risk of using up all the system memory and crashing both your application and the server it's running on. Pagination is absolutely essential unless you can be certain the number of records is small.
Using a before_filter makes it a lot easier to consolidate your various redundant find calls into one place and can make error handling a lot simpler.