9 Replies - 2756 Views - Last Post: 19 December 2011 - 06:42 PM Rate Topic: -----

#1 NotarySojac  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 53
  • View blog
  • Posts: 428
  • Joined: 30-September 10

Rails - Create method always leads to new method on error?

Posted 17 December 2011 - 09:27 AM

I'm trying to get an app up and running, and I keep hitting these snags. I'm basically in the employee#create action, and when the users inputs a jibberish email that doesn't exist in User.all, I want it to render/ redirect back to the same create page, with all the information the user plugged in to that HTML page (error and all). The only problem is that the first time the view looks as I would expect (with a create button), but once the user's input fails, the next page has a "Update Button", and after that is clicked, it leads to the error page No route matches "/employees"


(employees_controller.rb)
  .
  .
  .
  # When the user clicks "Make User employee" this method fires up
  # And sets it up
  def create
    # Get User by username...
    email = params[:user][:email]
    @user =  User.where(:email => email).first  

    @employee = Employee.create(params[:employee])

    if @user.nil?  # assume true
      flash[:error] = "Error:  User #{email} not found or something.  Hmmm..."
      @user = User.create(:email => email) # setup failing user object so it gets to view
      render :action => :index      #"index" # "/employees/index.html.erb"
      return
    else
    .
    .
    .





(views/employees/index.html.erb)
<h1>From this page, you can set users to 'employee' status</h1>
<br>
<p>Giving a user employee status, allows them to be able to see more data than regular customers can see.  </p>

<!--
When the user1.employee == nil, they are considered normal users.

But when you click Make Employee here, it will bring you to a form where you fill in their Employee settings.  
-->
<h1> Make New Employee </h1>
<br>

<%= render 'emp_form' %>

<h1> Remove Employee </h1>
User Name:<input type="text"></input><br>

<br><br>
<a href="#">Make Normal User</a>




(views/employees/_emp_form.html.erb)
<%= form_for(@employee, :url => { :action => "create", :controller => "employees" } ) do |f| %>
  <% if @employee.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@employee.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @employee.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= label 'user', 'email', 'User Login email (user must have created account already)' %><br />
    <%= text_field(:user, :email) %>
  </div>
  <div class="field">
    <%= f.label :employeeid, 'Employee ID (workpro)' %><br />
    <%= f.text_field :employeeid %>
  </div>
  <div class="field">
    <%= f.label :position_title %><br />
    <%= f.text_field :position_title %>
  </div>
  <div class="field">
    <%= f.label 'Date of Birth' %><br />
    <%= f.text_field :dob %>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>




(routes.rb)
  resources :employees


This post has been edited by NotarySojac: 17 December 2011 - 09:36 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Rails - Create method always leads to new method on error?

#2 noahgibbs  Icon User is offline

  • New D.I.C Head

Reputation: 8
  • View blog
  • Posts: 17
  • Joined: 18-December 11

Re: Rails - Create method always leads to new method on error?

Posted 18 December 2011 - 10:39 PM

First off, you're not checking the result of @employee.create. If the create succeeds, you want to redirect to update action and if it fails you want to redirect to the "new" action (probably, there's a couple of ways to deal with it).

That code would be in your controller but you didn't excerpt that far, so I'm not sure how it's working now.

Also, you'll want some kind of security on this if it's granting privileges. But you may already have that in a before_filter or something.
Was This Post Helpful? 0
  • +
  • -

#3 NotarySojac  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 53
  • View blog
  • Posts: 428
  • Joined: 30-September 10

Re: Rails - Create method always leads to new method on error?

Posted 19 December 2011 - 01:08 PM

I'm breaking from convention a bit (presumably) to do some hands on learning. My basic problem is that I'm explicitly telling it to

flash[:error] = "Error:  User #{email} not found or something.  Hmmm..."
15	    @user = User.create(:email => email) # setup failing user object so it gets to view
16	    render :action => :index  



(emphasis on the render :action => :index ) Because I'm filling in a bad @user.email on that view and am certain it will fail that first test and the above code will run. But instead of taking me to the exact same index page (with the input that the user filled in before already there) the button on the page changes from "create" to "update". And what's worse is, once I click "Update", in the second iteration, I am taken to an error screen.

I have "some" security in the before filters, but this bizarre error is preventing me from expanding on that security to prevent any potential mass assignment exploits.

I did a quick youTube that walks through what I'm saying, so maybe that will explain the situation better.


Was This Post Helpful? 0
  • +
  • -

#4 noahgibbs  Icon User is offline

  • New D.I.C Head

Reputation: 8
  • View blog
  • Posts: 17
  • Joined: 18-December 11

Re: Rails - Create method always leads to new method on error?

Posted 19 December 2011 - 01:15 PM

NotarySojac, one thing you should do is check your logs (log/development.log, probably). They'll tell you whether you're seeing the same action (i.e. controller code) and the same template (i.e. what you pass to the render call) each time. It will also show you any redirects you may hit. You may be going from "create" to "update" by changing what action you're doing with a redirect.
Was This Post Helpful? 0
  • +
  • -

#5 noahgibbs  Icon User is offline

  • New D.I.C Head

Reputation: 8
  • View blog
  • Posts: 17
  • Joined: 18-December 11

Re: Rails - Create method always leads to new method on error?

Posted 19 December 2011 - 01:21 PM

NotarySojac, also you're only rendering the "index" view if @user isn't created. So the second time you enter the same bad email address, there's already a user and you probably fail because it can't find a view for create -- there isn't one by default. Instead, it's a POST that expects you to redirect somewhere, or render a different view.

So you may just need to "redirect_to :action => :index" or something if it succeeds - you'll be on a different page, which is almost always what you want after doing a POST to a create action. Again, you didn't excerpt that part of the controller's create method.
Was This Post Helpful? 0
  • +
  • -

#6 NotarySojac  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 53
  • View blog
  • Posts: 428
  • Joined: 30-September 10

Re: Rails - Create method always leads to new method on error?

Posted 19 December 2011 - 02:09 PM

View Postnoahgibbs, on 19 December 2011 - 01:15 PM, said:

NotarySojac, one thing you should do is check your logs (log/development.log, probably). They'll tell you whether you're seeing the same action (i.e. controller code) and the same template (i.e. what you pass to the render call) each time. It will also show you any redirects you may hit. You may be going from "create" to "update" by changing what action you're doing with a redirect.



Ok, this is the log for the first successful click, and then the second one which leads to the error page. To my novice eyes, there's not too much in there to explain what it's thinking.

Started POST "/employees" for 127.0.0.1 at 2011-12-19 14:49:53 -0600
  Processing by EmployeesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"BnIMbBLip864cWCm1TOLbfNtXH5kEr5rRV/zXa+S7Fo=", "user"=>{"email"=>"asdf"}, "employee"=>{"employeeid"=>"", "position_title"=>"fflo", "dob"=>""}, "commit"=>"Create Employee"}
  User Load (0.1ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
  User Load (0.1ms)  SELECT `users`.* FROM `users` WHERE `users`.`email` = 'asdf' LIMIT 1
  SQL (0.1ms)  BEGIN
  SQL (0.8ms)  describe `employees`
  AREL (0.2ms)  INSERT INTO `employees` (`employeeid`, `name`, `position_title`, `origin_date`, `dob`, `created_at`, `updated_at`, `user_id`) VALUES (NULL, NULL, 'fflo', NULL, NULL, '2011-12-19 20:49:53', '2011-12-19 20:49:53', NULL)
  SQL (3.1ms)  COMMIT
  SQL (0.1ms)  BEGIN
  SQL (0.1ms)  SELECT 1 FROM `users` WHERE (LOWER(`users`.`email`) = LOWER('asdf')) LIMIT 1
  SQL (0.2ms)  ROLLBACK
Rendered employees/_emp_form.html.erb (7.0ms)
Rendered layouts/_navigation.html.erb (2.1ms)
Rendered layouts/_flash.html.erb (0.7ms)
Rendered layouts/_footer.html.erb (0.4ms)
Rendered employees/index.html.erb within layouts/application (20.4ms)
Completed 200 OK in 163ms (Views: 24.5ms | ActiveRecord: 4.7ms)


Started POST "/employees" for 127.0.0.1 at 2011-12-19 14:50:35 -0600

ActionController::RoutingError (No route matches "/employees"):
  

Rendered /usr/local/rvm/gems/ruby-1.9.2-p180/gems/actionpack-3.0.7/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (1.6ms)



Quote

NotarySojac, also you're only rendering the "index" view if @user isn't created. So the second time you enter the same bad email address, there's already a user and you probably fail because it can't find a view for create -- there isn't one by default. Instead, it's a POST that expects you to redirect somewhere, or render a different view.

So you may just need to "redirect_to :action => :index"


OK, I think I'm following you. When I use redirect_to :action => :index it redirects to the new page just fine. But the problem is that now the user has to fill in the fields from scratch. There must be a simple way around this right?


Here's the rest of the controller, but it doesn't come into play because right now, I'm only testing the invalid user email side of things. I want to get that working smoothly before I start moving on. I've been considering writing some javascript that will fill in the missing info using flash notifications, but I'm assume rails has something built-in to do that for me.


class EmployeesController < ApplicationController
  
  def index
    @employee = Employee.new
  end

  # When the user clicks "Make User employee" this method fires up
  # And sets it up
  def create
    # Get User by username...
    email = params[:user][:email]
    @user =  User.where(:email => email).first  

    @employee = Employee.create(params[:employee])
    p @employee

    if @user.nil?
      flash[:error] = "Error:  User #{email} not found or something.  Hmmm..."
      @user = User.create(:email => email)
      render :action => :index      #"index" # "/employees/index.html.erb"
      return
    else
    
      # Make sure user is not already set to an employee
      #@employee = Employee.new
      
      @user.employee = @employee
  
      @user.save
      # print "Employee Created!"
      if !@user.employee.nil?
        flash[:success] = "User successfully set to employee!"
        redirect_to @user
      else
        flash[:error] = "An error occured creating employee..."
        p @user.employee
        redirect_to @user
      end
    
    end
  end
  
  def destroy
    
  end
end


Was This Post Helpful? 0
  • +
  • -

#7 noahgibbs  Icon User is offline

  • New D.I.C Head

Reputation: 8
  • View blog
  • Posts: 17
  • Joined: 18-December 11

Re: Rails - Create method always leads to new method on error?

Posted 19 December 2011 - 02:38 PM

Okay, yeah, the routing error is weird. Usually you'd see a different template error if it's a template problem (and I think you have a template problem).

So you could replace that redirect with a render call, so that you're always rendering the index template. That might work. You could also pass the appropriate parameters through the redirect so that you've still got what the user entered. Something like:

 redirect_to :action => :index, :employee => params[:employee] 


But that's only if you can still edit on the index (controller) action, and you probably can't. This is all a little weird because you're doing a really weird mapping of semantics to REST calls - usually an "employees" controller's create action would create an employee (which you're kinda-sorta doing, except an employee is also sort of a user) and the index action would just display a list of employees (which doesn't seem to be at all what you're doing).

My first guess here so far is to try always calling "render :action => :index" and see if that fixes the params thing while still letting you edit.
Was This Post Helpful? 0
  • +
  • -

#8 NotarySojac  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 53
  • View blog
  • Posts: 428
  • Joined: 30-September 10

Re: Rails - Create method always leads to new method on error?

Posted 19 December 2011 - 03:51 PM

It almost worked =/ I got the information in the url

http://0.0.0.0:3000/employees?employee[dob]=&employee[employeeid]=&employee[position_title]=ffdsdf


This approach I'm taking is how I would do things if it were a C# environment.

What would you do for a situation where you want the owner to be able to mark certain users as "Employees" to differentiate those accounts from customer accounts? (e.g. Employees can see everyone's reciepts, whereas Customers can only see there own)

I've been stuck at this point for literally more than a month, always having to stop and flesh out new html/css with the photoshop designer (so the transaction database isn't even online yet).

This post has been edited by NotarySojac: 19 December 2011 - 03:55 PM

Was This Post Helpful? 0
  • +
  • -

#9 noahgibbs  Icon User is offline

  • New D.I.C Head

Reputation: 8
  • View blog
  • Posts: 17
  • Joined: 18-December 11

Re: Rails - Create method always leads to new method on error?

Posted 19 December 2011 - 04:16 PM

If it were me, I'd actually just add a flag to "User" to say whether they were an employee -- or maybe an enumeration/integer for what 'role' they have, with 'normal' and 'employee' and maybe 'admin' being options. Then you wouldn't have this separate employee structure hanging around screwing you up. You'd have to make sure that role/employee didn't ever get mass-assigned, but that's not too bad.

That's only if 'employee' doesn't have a lot of extra SQL fields on top of 'user', though. If you need lots more information about an employee, that's harder and you probably need a join table like you have :-/

If you're passing the params like that, I don't know why you aren't seeing them. Your partial for the form should totally be using those (and looks like the code for it is fine). You can view source on the page and check the 'name' attribute of your fields and make sure it looks something like "employee[field_name]" like you want, but it should be...
Was This Post Helpful? 1
  • +
  • -

#10 NotarySojac  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 53
  • View blog
  • Posts: 428
  • Joined: 30-September 10

Re: Rails - Create method always leads to new method on error?

Posted 19 December 2011 - 06:42 PM

kk, thanks a lot for your advice. I'll add a roles array to the User model, that's a really good idea. I do have an employees table that I need to store legacy information in and lots of stuff so what I think I'm going to do is just have it redirect to a new page without preserving information and maybe come back to it with javascript if I start getting complaints (it's a small shop where I'm implementing this so the owner probably won't notice).

Edit:
Looks like when you build the form using form_for(@employee), if @employee is anything other than a brand new Employee object, it will make the button "Update", instead of what I desired "Create".

This post has been edited by NotarySojac: 19 December 2011 - 08:12 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1