Rails 4 - Updating Specific Attributes in model - ruby-on-rails

I'm building a marketplace app (rails 4) where sellers can list items to sell. I have a seller profile form where users enter some details about their brand.
I'm not able to get the record to update with user inputs. The form submits without any error but the model is not updated.
Code below. Demo at http://mktdemo.herokuapp.com/seller/18 (login: test#test.com / pwd: test1234)
route:
match "/seller/:id", to: "users#sellerprofile", via: [:get, :put], as: :sellerprofile
my form:
<%= form_for(#user, url: sellerprofile_path(id: current_user.id), method: :put, html: { :class => 'edit_profile', :multipart => true }) do |f| %>
<div class="form-group">
<%= f.label :your_story %><i> (required)</i>
<%= f.text_area :profilestory, class:"form-control" %>
</div>
<div class="form-group">
<%= f.label :profile_image %><i> (required)</i>
<%= f.file_field :profileimage, class:"form-control" %>
</div>
<div class="form-group">
<%= f.submit class:"btn btn-primary" %>
</div>
<% end %>
user_controller:
def sellerprofile
#user = User.find(params[:id])
#user.update_attributes(:profilestory => params[:profilestory], :profileimage => params[:profileimage])
end
For the image, I'm using paperclip and have the has_attached... code in my model.
UPDATE:
Here is my user_params in controller:
def user_params
params.require(:user).permit(:bankaccname, :profileimage, :profilestory)
end
When I use #user.update(user_params) in the sellerprofile method, I get a params :user not found error. This error occurs when I load the form (not on submit). Error is in the line params.require(:user)
UPDATE 2:
Here is the update method. I'm using this for another form that takes in some bank account data so I'm not sure if I can modify this for the profile form.
def update
#user.attributes = user_params
Stripe.api_key = ENV["STRIPE_API_KEY"]
token = params[:stripeToken]
recipient = Stripe::Recipient.create(
:name => user_params["bankaccname"],
:type => "individual",
:bank_account => token
)
#user.recipient = recipient.id
respond_to do |format|
if #user.save
format.html { redirect_to edit_user_url, notice: 'Your account was successfully updated.' }
else
format.html { render action: 'edit' }
end
end
end

If you look at your question, it says:
When I use #user.update(user_params) in the sellerprofile method, I get a params :user not found error. This error occurs when I load the form (not on submit)
This line tells us that there is something wrong in the action where your form is rendered. I mean the url you hit in browsers address bar to display your form
And in your comment you told me that the url for rendering your form is /seller/:id and now lets look at your form code
<%= form_for(#user, url: sellerprofile_path(id: current_user.id), method: :put, html: { :class => 'edit_profile', :multipart => true }) do |f| %>
Notice the url used in the form? You are using the same action to render your form and then after submitting form it'll again take you to same action which is wrong. You should make two different routes. One to render your form and other one to create it. To explain it further, if you look at your code
def sellerprofile
#user = User.find(params[:id])
#user.update_attributes(user_params)
end
So when you hit /seller/:id it takes you to sellerprofile method and hence code inside your sellerprofile method fires up and it tries to update your user because of this line #user.update_attributes(user_params) but there are no user_params as you didn't submit any form so you get a params :user not found errorr
Fix:
Just make two different routes, one to render your form and another one to create your record:
match "/seller/:id/new", to: "users#sellernew", via: [:get], as: :sellernewprofile
match "/seller/:id", to: "users#sellerprofile", via: [:put], as: :sellerprofile

Related

Ruby on rails table not saving an additional object

I have a has_many :active_posts table in my User model. I'm fairly confident that it is set up correctly. However, when I try to add an already existing object to the table, it doesn't seem to work. Any help would be appreciated!
model user.rb
def addpost(other_post)
active_posts << other_post
end
the view _feed.html.erb
<%= form_for #training_post, :html => {:class => "form-inline"}, url: confirm_training_post_path(post), method: :patch do |f| %>
<div class="form-group">
<%= f.submit "Confirm", class: "btn-primary btn-xs form-control" %>
</div>
<% end %>
the controller posts_controller.rb
def confirm
#post = Post.find_by(id: params[:id])
#user = User.find(params[:id])
#post.toggle!(:confirm)
#post.update_attribute(:propreceived, active_post_params[:propreceived])
current_user.addpost(#post)
current_user.deletepassivepost(#post)
redirect_to root_url
end
It sounds like you're not saving the user's active_posts, instead just adding it to the collection. You need to save the user's active_posts somehow.
Assuming active_posts has a schema of user_id and post_id:
user.rb
def add_post(post)
self.active_posts.create(:post => post)
end

Rails form rendering wrong URL after validation errors (not keeping passed parameter)

On a project show page, I pass a very simple parameter on my 'create new task' that stores which project its from:
#project.id), :class => "btn btn-info col-md-12" %>
so that when i create a new task for it, it stores it in the URL on my new task form like this:
http://localhost:3000/task/new?project_id=5
My New form is as follows:
<div class="container sign-in-register">
<div class="authform">
<%= form_for #task, :html => {:multipart => true} do |f| %>
<h3>Add a task for this project...</h3><br/>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= hidden_field_tag 'project_id', #project_id %>
<%= f.fields_for :taskrelationships do |ff| %>
<%= ff.hidden_field :taskproject_id, value: #project_id %>
<%= ff.label :task_url %>
<%= ff.text_field :task_url, class: 'form-control' %>
<% end %>
<br clear="all">
<%= f.submit "Save Task", class: "btn btn btn-info" %>
<% end %>
</div>
</div>
As you can see i'm using nested attributes in the form (I am creating both a task and a TaskRelationship. Now, when I try to save without filling out all the required fields a validation is thrown but for some reason it redirects me to:
http://localhost:3000/tasks
instead of the original:
http://localhost:3000/tasks/new?project_id=5
I have read many posts and none seem to answer this particular case. The stackO post below was close but when I try it with task instead of user it still cannot find the task_ID
Render error on new page with customize url like http://localhost:3000/education_informations/new?user_id=10
How can I have rails simply render the same exact url as I started with - it seems like this should be easy so must be missing something small.
My controller actions:
def new
#project_id = params[:project_id]
#task = Task.new
#task.taskrelationships.build
end
def create
#project = Project.find(params[:project_id])
#task = Task.new(task_params)
if #task.save
flash[:success] = "This task has been added."
#task.taskrelationships.create!(#taskrelationships_params)
redirect_to tasks_project_path(#project)
else
#task.taskrelationships.build(#taskrelationships_params)
flash[:alert] = #task.errors.full_messages.to_sentence
render :new
end
end
private
def task_params
#taskrelationships_params = params.require(:task).permit(taskrelationships_attributes: [
:task_url,
:taskproject_id
])[:taskrelationships_attributes]["0"]
params[:task].delete(:taskrelationships_attributes)
params.require(:task).permit(
:name,
:user_id,
taskrelationships_attributes: [
:task_url,
:taskproject_id
]
).merge(owner: current_user)
end
UPDATE W / ROUTES
resources :projects do
resources :reviews, except: [:destroy]
member do
get :tasks
end
end
resources :tasks
resources :taskrelationships, only: [:create, :destroy] do
post :vote, on: :member, controller: "task_relationships"
end
thanks for any assistance...
Ok firstly an explanation as to what is going on here:
When you invoke http://localhost:3000/task/new?project_id=5 you are actually being routed to the new action on the task controller (with a project_id param).
Your new action then sets the variables and rails will render the new.html.erb which contains your new task form.
When you submit the form it actually is doing a http POST to /tasks, which routes to the create action of your tasks controller. That url and http method is a result of what is generated from the form_for helper:
<%= form_for #task, :html => {:multipart => true} do |f| %>
This is why the url changes from /tasks/new?project_id=5 to /tasks
Now the create action if it fails the validation simply renders the new form - it is not redirecting anywhere - the url remains unchanged from what it was when it entered this action - meaning, it remains as /tasks.
You do not actually need to navigate to /tasks/new?project_id=5 to render the new form but what you do need to do is set #project_id in the controller so the view has access to that variable (just as it does in the new action):
def create
#project = Project.find(params[:project_id])
#task = Task.new(task_params)
if #task.save
flash[:success] = "This task has been added."
#task.taskrelationships.create!(#taskrelationships_params)
redirect_to tasks_project_path(#project)
else
#task.taskrelationships.build(#taskrelationships_params)
#project_id = #project.id
flash[:alert] = #task.errors.full_messages.to_sentence
render :new
end
end
So, to clarify the change in url is not a redirection it's just that the form is posting to a different url than /tasks/new, and this is actually just a cosmetic issue.
Now if it is a concern to you, you can change the routing to something like the following:
resources :tasks, except: [:create, :new]
post 'new_task' => 'tasks#create'
get 'new_task' => 'tasks#new'
This is mapping the POST and GET http methods to /new_task so the url appears the same for the new and create action invocations. Note you do need to change the url in the form_for helper to use this new route:
<%= form_for #task, url: 'new_task', multipart: true do |f| %>
Since Rails default behaviour in forms is with remote: true, you can move the content of the form to a partial(let's name it _my_form.html.erb), add to the controller action (let's say in create action):
respond_to do |format|
format.js {}
end
Then add a create.js.erb file where you will render the form partial
$("#form").html(
"<%= j render partial: 'my_form', locals: { entity: #entity } %>"
);
Thus, validation errors and all attributes will be accessible inside the form and there is no need to hack the "Rails approach"
I had to adapt and experiment with the currently accepted answer,
and the following ended up working well (using schools rather than tasks):
In config/routes.rb:
resources :schools do
...
end
post 'schools/new' => 'schools#create'
And create the form like:
= simple_form_for [#school], url: 'new' do |f|
Thus the path /schools/new was preserved on validation :)

cannot update attribute within users model in custom action

I am using the Gem Devise for users in my application. I added the role attribute within users that is set to nil. After I sign in, within the application controller I have a redirect that goes to a custom action within the users controller and view called binary_selection if current_user.role = nil. The code is below
application_controller.rb:
def after_sign_in_path_for(resource)
if current_user.role.nil? ## temporary solution
#update_path(resource)
binary_selection_path(resource)
else
root_path(resource)
end
end
users_controller.rb:
def binary_selection
#user = current_user
respond_to do |format|
if #user.update_attributes(params[:user][:role])
format.html { redirect_to root_url, notice: "#{#user.name} was updated." }
else
format.html { render action: "edit" }
end
end
end
views/users/binary_selection.html.erb:
<%= form_for #user, url: binary_selection_path(#user), html: { method: :patch } do |f|
%><%= current_user %>
<div class = "form-group">
<%= f.label :role %>
<%= f.text_field :role, class: 'form-control', placeholder: "Enter wiki title", id: 'wiki_title' %>
</div>
<div class = "form-group">
<%= f.submit class: 'btn btn-success' ,id: 'wiki_submit' %>
</div>
<% end %>
config/routes.rb:
Rails.application.routes.draw do
devise_for :users
get "/users" => "users#binary_selection", as: 'binary_selection'
resources :users
end
When I get redirected to the binary_selection view I get this error:
NoMethodError in UsersController#binary_selection
undefined method `[]' for nil:NilClass
where it highlights this line within the users controller:
if #user.update_attributes(params[:user][:role])
I also noticed it has this for the params on the error page:
{"format"=>"13"}
You redirect your user after sign_in to the binaray_selection_path. This will result in a HTTP GET request. In your users_controller you try to get a attribute from the params that simple does not exist. There is no params[:user], because the form was not sent yet.
You need to redirect the user to a page were the form is rendered.
I advise to read this guide: http://guides.rubyonrails.org/getting_started.html#getting-up-and-running
Your form is not submitting the values properly may be. So inspect your params in the binery select action.
record#update_attributes doesn't take a single value, it accepts hash. So the proper code should be something like:
rails version < 4
if #user.update_attributes(params[:user])
in rails 4.*
if #user.update_attributes(user_params)
in controller make sure you have permitted the user parameters.

Rails form adding empty entry via model

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

Routing error when trying to use same view for update and create flows (Rails 3)

My overall use case:
I have a Listing model that has many images. The Listing detail page lists all the fields that can be updated inline (through ajax).
I want to be able to use the same view for both update listing and create new listing.
My listing controller looks as follows:
def detail
#listing = Listing.find(params[:id])
#image = Image.new #should this link somewhere else?
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #listing }
end
end
def create
# create a new listing and save it immediately. Assign it to guest, with a status of "draft"
#listing = Listing.new(:price_id => 1) # Default price id
# save it to db
# TODO add validation that it has to have a price ID, on record creation. So the view doesn't break.
#listing.save
#image = Image.new
# redirect_to "/listings/detail/#listing.id" #this didn't work
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #listing }
end
end
The PROBLEM
I'm using a partial that shows the same form for the create view and the detail view.
This works perfectly except for one thing:
When I pull up
http://0.0.0.0:3000/listings/detail/7, it works perfectly.
When I pull up
http://0.0.0.0:3000/listings/new, I get the following error:
Showing /Applications/MAMP/htdocs/rails_testing/feedbackd/app/views/listings/_edit_form.html.erb where line #100 raised:
No route matches {:action=>"show", :controller=>"images"}
Extracted source (around line #100):
97: <!-- Form for new images -->
98: <div class="span-20 append-bottom">
99: <!-- <%# form_for :image, #image, :url => image_path, :html => { :multipart => true } do |f| %> -->
100: <%= form_for #image, :url => image_path, :html => { :multipart => true } do |f| %>
101: <%= f.text_field :description %><br />
102: <%= f.file_field :photo %>
103: <%= submit_tag "Upload" %>
What I think the issue is:
When I upload a new image (I'm using Paperclip), it requires the listing_id to create the image record. Since the listing_id isn't passed in with listings/new it can't find the listing_id. How can I pass in the id? Via a redirect? What's the best way to solve this? Thank you.
It seems that the problem is that you are trying to submit to a URL that doesn't exist. If you use a form like this:
<%= form_for #image, :html => { :multipart => true } do |f| %>
Then in your routes.rb file you should have:
resources :images
And you should have an ImagesController with a create action defined. The ImagesController#create action will get called when you submit this form.
The problem is in ur routes.rb file. U have not defined the path, thats why it is giving this error. This might help u
http://guides.rubyonrails.org/v2.3.8/routing.html#restful-routing-the-rails-default
Thank you, your comments have all been helpful.
This is how I wound up solving it:
I added a route for images/new to point to imageController -> Create
<%= form_for #image, :url => "/images/new/#{#listing.id}" , :html => { :multipart => true } do |f| %>
<%= f.text_field :description %><br />
<%= f.file_field :photo %>
<%= submit_tag "Upload" %>
<% end %>

Resources