Hello I'm very new to ruby on rails. Here i have form
<%= form_tag do %>
<%= text_field_tag :fullname, params[:fullname], placeholder: 'fullname' %>
.
.
.
<%= submit_tag "save" %>
<% end %>
Those form is to update model data. In my controller I have
def updateUser
user = Users.find(session[:user_id])
user.fullname = params[:fullname]
user.save
render 'profile'
end
It's not working (data doesn't updated), but when I tried
def updateUser
user = Users.find(session[:user_id])
user.fullname = 'david'
user.save
render 'profile'
end
It's working (the data updated). I don't know where did I go wrong, please kindly help me. Sorry for asking such easy question, I'm a newbie to Ruby (and so does Rails), I searched but didn't get a suitable answer for this case. Thank you
I'm very new to ruby on rails
Welcome - let me give you some ideas!
--
Form
Firstly, your form_tag is not created properly. You need to put a route in this (so it knows where to submit the data):
<%= form_tag your_path_here do %>
This is for the form_tag helper, however, as you're editing an object, you'll probably be better using the form_for helper - which takes an actual object (value):
<%= form_for #user do |f| %>
<%= f.text_field :full_name %>
<%= f.submit "Submit" %>
<% end %>
This type of form has to be used with the resourceful structure of Rails, which is my second point...
--
Resources
Rails is built around the idea of a resourceful infrastructure (where every data object is a resource). If you're updating / editing an object, the typical explanation is that you'll be editing a resource, and consequently will want to employ rails' resourceful structure to handle it:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:edit, :update, :show]
def index
#users = User.all
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
#user.save
end
def edit
end
def update
#user.update(user_params)
end
private
def user_params
params.require(:user).permit(:fullname, :etc)
end
def set_user
#user = User.find params[:id]
end
end
This will allow you to define the resourceful routes for this:
#config/routes.rb
resources :users
Using this setup with form_for will work for you
Didn't notice in the beginning. Your form is incorrect. You did not specify a URL for action, and you put your submit tag within a link so basically your link is getting called not your form submitted.
<%= form_tag '/userEdit' do %>
<%= text_field_tag :fullname, params[:fullname], placeholder: 'fullname' %>
.
.
.
<%= submit_tag "save" %>
<% end %>
Make sure that you have specified a route for userEdit post method.
Related
I'm working on messaging system between User and AdminUser. The User part is ready now I'm struggling how to allow Admin to send a reply to a conversation started by a User, inside of ActiveAdmin.
Code below:
# app/admin/conversations.rb
ActiveAdmin.register Conversation do
decorate_with ConversationDecorator
# ...
controller do
def show
super
#message = #conversation.messages.build
end
end
end
app/views/admin/conversations/_show.html.erb
# ...
<%= form_for [#conversation, #message] do |f| %>
<%= f.text_area :body %>
<%= f.text_field :messageable_id, value: current_user.id, type: "hidden" %>
<%= f.text_field :messageable_type, value: "#{current_user.class.name}", type: "hidden" %>
<%= f.submit "Send Reply" %>
<% end %>
<% end %>
Which gives me an error:
First argument in form cannot contain nil or be empty
Extracted source (around line #51):
51 <%= form_for [#conversation, #message] do |f| %>
When I tried to debug it turned out #message = nil inside of _show.html.erb. How is that possible if I defined #message inside of ActiveAdmin controller ?
[EDIT]
In case you're curious, ConversationController below:
class ConversationsController < ApplicationController
before_action :authenticate_user!
def index
#admins = AdminUser.all
#conversations = Conversation.all
end
def new
#conversation = Conversation.new
#conversation.messages.build
end
def create
#conversation = Conversation.create!(conversation_params)
redirect_to conversation_messages_path(#conversation)
end
end
#routes
resources :conversations do
resources :messages
end
Normally you set up instance variables in your controller, and then Rails later does an implicit render of the view once the controller method completes.
However, it is possible to do an explicit render of the view, by calling something like render action: or render template: while the controller method is running, and presumably this is happening within the call to super.
See the Layout and Rendering Rails Guide for more information.
You'll need to move the assignment to be before the call to super.
You may also need to replace #conversation with resource in the ActiveAdmin controller (this is an ActiveAdmin/InheritedResources gem thing).
I am getting the following error when trying to use form_for in my Rails application:
undefined method `to_key' for #<Table::ActiveRecord_Relation:0x8a09ca8>
My config/routes.rb is:
root 'welcome#index'
post 'foo', as: 'foo', to: 'welcome#index'
The controller is:
class WelcomeController < ApplicationController
def index
#tables = Table.all
end
def test
#tables = Table.all
end
end
And the welcome/index.html.erb view is:
<p>
<%= form_for #tables, :url => foo_path do |t| %>
<%= t.text_area :name %>
<% end %>
</p>
I've tried to do the url workaround that had been suggested in the documentation, but I'm still getting the same error.
Does anyone know what I am doing wrong? I would like to understand this bug a bit more so I can better deal with it.
As per your code, index is returning a collection. However your view tries to define a form for it. This is unlikely going to be succeed.
Form is for an object, not for collections.
Perhaps you can do something like
def new
#table = Table.new
end
and in new.html.erb
<%= form_for #table do |f| %>
...
<% end %>
And if you would like to stick with index.html.erb with a form. Then you have to edit your routes for index action and also in controller it should be for creating a new object.
def index
#table = Table.new
end
Hope it helps!
I see your code have 3 not true things
As RESFUL standard then:
index action always go through with get action so in route file you should define again same that:
root "wellcome#index"
get "foo", to: "wellcome#index", as: :foo
form_for usually use with model object but not collect as you use #tables, if model object not save into database form_for using to create 1 object to database, otherwise form_for using update that object
if you want create form at index action you can follow me:
def index
#tables = Table.all
#table = Table.new
end
index.html.erb file
<%= form_for #table do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
you need create tables_controller to process request from form send to server. you run: rails g controller tables
In table_controller.rb you write same as:
def create
#table = Table.new table_params
if #table.save
redirect_to root_path, notice: "success"
else
redirect_to root_path, alert: "fail"
end
end
private
def table_params
params.require(:table).permit :name
end
so that. end. Have nice day!
I have a form_for #user to update a column in user model .
I have given html method as get and submitting to action look like
#user = User.find(params[:id])
#user_update_attribute(:phno,params[:phno])
and in view its look like
<%= form_for :#user, url: addphno_addphno_path , html: { method: :get } %>
The issue is I am not able to get data in controller action.the error is
could not find record of "id="
If you wanted to have a separate "phoneno" action:
#config/routes.rb
resources :users do
match :addphone, via: [:get, :post]
end
#app/views/users/add_phone_no.html.erb
<%= form_for #user, user_addphone_path(#user) do |f| %>
<%= f.text_field :number %>
<%= f.submit %>
<% end %>
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def addphone
#user = User.find params[:id]
#user.update( update_params ) if request.post?
end
private
def update_params
params.require(:user).permit(:phno)
end
end
If you wanted to use the update action (as is convention):
#config/routes.rb
resources :users
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def edit
#user = User.find params[:id]
end
def update
#user = User.find params[:id]
#user.update user_params
end
private
def user_params
params.require(:user).permit(:phno)
end
end
This will allow you to call:
#app/views/users/edit.html.erb
<%= form_for #user do |f| %>
<%= f.text_field :phno %>
<%= f.submit %>
<% end %>
Bottom line is that you should be using the second batch of code if you're updating your #user object.
I originally thought you wanted to add a phone number as associative data to your #user... but it seems that you just wish to add a phone number for the user. To do this, the above code will suffice.
This question already has answers here:
form_for with nested resources
(3 answers)
Closed 7 years ago.
simple question that I am not able to solve some how.
I am trying to mimic the first few steps of this Railscast Episode. I have a picture-Model and I am trying to instantiate an object of this kind on the index page. Therefor I am using those lines:
index.erb.html
<%= form_for Picture.new do |f| %>
<%= f.label :image, "Upload" %>
<%= f.file_field :image, multiple: true %>
<% end %>
But I am getting this error:
undefined method `pictures_path' for #<#<Class:0xb465af0>:0x58fc488>
If I remove the form it works perfectly. Seems simple but I can't solve it. I would appreciate some help.
PicturesController
class PicturesController < ApplicationController
respond_to :html
def index
#house = House.find(params[:house_id])
#pictures = #house.pictures
respond_with(#pictures)
end
def new
#picture = Picture.new
end
def create
end
def destroy
end
private
def picture_params
params.require(:picture).permit(:id, :name, :house_id, :image, :_destroy)
end
routes.rb
Rails.application.routes.draw do
resources :houses do
resources :pictures, only: [:index]
end
end
With your given routes info, you don't really have pictures_path. You have only these routes (if you do a rake routes):
house_pictures GET /houses/:house_id/pictures(.:format) pictures#index
houses GET /houses(.:format) houses#index
That's why you are getting that error.
You have access to house_pictures_path BUT NOT pictures_path.
To solve this issue, you have to use house_pictures_path and send the #house and #pictures as argument to that. something like this:
<%= form_for [#house, #house.pictures.build] do |f| %>
<%= f.label :image, "Upload" %>
<%= f.file_field :image, multiple: true %>
<% end %>
Your pictures resource is nested within your houses resource. There is no route to allow you to create a new Picture without a House to provide the surrounding context, and so form_for cannot automatically produce a URL if you give it only Picture.new.
You need to give it both a house, and a picture.
Typically, your would do something like this:
form_for [#house, #house.pictures.new] do |f|
I'm having trouble getting my redirect and error messages to work. From what I've read you cant get a forms errors to show up when you use redirect so I am trying to use render after it fails.
I have a new post form on a topic page. The url is "topic/1". If you make a post about the topic and something is wrong with the input I want it to go back to the page at topic/1 and display errors and I cant figure out how to get it to go back. Redirect (:back) does what I want but doesnt show the forms errors.
The form on the topic's show.html page:
<%= form_for(#post) do |f| %>
<%= render 'shared/post_error_messages' %>
<%= f.label :title, "Post Title" %>
<%= f.text_field :title %>
<%= f.label :content %>
<%= f.text_field :content %>
<%= f.hidden_field :parent_id, value: 0 %>
<%= f.hidden_field :topic_id, value: #topic.id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.submit "Create Post" , class: "btn btn-small btn-primary" %>
<% end %>
Create action in the Posts controller
def create
#post = Post.new(post_params)
#topic = Topic.find_by(id: params[:topic_id])
if #post.save
redirect_to #post
else
#topic = Topic.new
render "/topics/show"
end
end
I guess I'm mostly trying to do the render with the id from the page that the form was originally on.
Errors
The problem isn't anything to do with the way you're rendering the form (render or redirect) - it's to do with the way you're handling your ActiveRecord object.
When you use form_for, Rails will append any errors into the #active_record_object.errors method. This will allow you to call the following:
form_for error messages in Ruby on Rails
<%= form_for #object do |f| %>
<% #location.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
This only works if you correctly create your ActiveRecord object, which you seem to do
--
Nested
#config/routes.rb
resources :topics do
resources :posts, path: "", path_names: {new: ""}, except: [:index] #-> domain.com/topics/1
end
You'll be much better using the following setup for a nested route:
<%= form_for [#topic, #post] do |f| %>
...
<% end %>
This allows you to create a form which will route to the topics_posts_path, which is basically what you need. The controller will then balance that by using the following:
#app/controllers/topics_controller.rb
Class TopicsController < ApplicationController
def new
#topic = Topic.find params[:topic_id]
#post = Post.new
end
def create
#topic = Topic.find params[:topic_id]
#post = Post.new post_params
end
private
def post_params
params.require(:post).permit(:attributes)
end
end
You are overwriting the Topic you original found with a brand new, empty one - which shouldn't be necessary and which is causing the posts related to it to disappear.
Also - if your topic and post are related - you should create the post on the appropriate association #topic.posts instead of the main Post class.
The #topic.posts.new means that the post's topic-id is automatically updated with the value of the #topic.id ... which means you don't need to set it in the hidden-field on the form.
In fact it's better if you don't - just delete that hidden field entirely.
If you add that to the first time you get a new post too (eg in topics/show) then you won't need to pass in a value to the hidden-field.
Also I'd do the same for all the other hidden-fields on the server-side too. You don't really want the user to use firebug to hack the form and add some other user's id... so do it in the create action and don't bother with the hidden field
This should work:
def create
#topic = Topic.find_by(id: params[:topic_id])
#post = #topic.posts.new(post_params)
#post.user = current_user
#post.parent_id = 0
if #post.save
redirect_to #post
else
render "/topics/show"
end
end
if it doesn't - let me know what error messages you get (so we can debug)