shakycode

Joined

5,390 Experience
2 Lessons Completed
3 Questions Solved

Activity

Posted in Ransack undefined method _path in Rails 4.2.1

I'm working on a simple CRUD Asset Management app and I want to use Ransack. I think I have this setup properly in my view and controller but each time the index view is hit I get the exception:

undefined methodassets_path' for #<#:0x007fa5f353e9e0>`

Here is my view:

index.html.erb

    <div class="pull-right">
    <%= search_form_for @q do |f| %>
      <%= f.search_field :asset_name_cont, placeholder: 'Search...' %>
    <% end %>
  <table class="table table-striped">
  <thead>
    <tr>
      <th>Asset Number</th>
      <th>Asset Name</th>
      <th>Serial Number</th>
      <th>Model</th>
      <th>Manufacturer</th>
      <th>Asset Type</th>
      <th>Actions</th>
    </tr>
  </thead>

  <tbody>
   <% @assets.each do |a| %>      
      <tr>
        <td><%= a.asset_number %></td>
        <td><%= a.asset_name %></td>
        <td><%= a.asset_serial %></td>
        <td><%= a.asset_model %></td>
        <td><%= a.asset_manuf %></td>
        <td><%= a.asset_type.try(:name) %></td>
        <td><%= link_to 'View', inventory_path(a), :class => 'btn btn-mini btn-info' %> <%= link_to 'Edit', edit_inventory_path(a), :class => 'btn btn-mini btn-warning' %></td>

      </tr>
  </tbody>
  <% end %>
<%= will_paginate @assets %>

Here is my controller excerpt: inventory_controller.rb

  def index
    @q = Asset.ransack(params[:q])
    @assets = @q.result.order("asset_number ASC").paginate(:page => params[:page], :per_page => 10)
  end

And here is my model (with annotation of the fields)

asset.rb

 id              :integer          not null, primary key
 asset_number    :string
 asset_shortname :string
 asset_name      :string
 asset_desc      :text
 asset_serial    :string
 asset_model     :string
 asset_manuf     :string
 asset_type_id   :integer
 created_at      :datetime         not null
 updated_at      :datetime         not null
 asset_location  :string


class Asset < ActiveRecord::Base
    extend FriendlyId
        friendly_id :asset_name, use: :slugged
        validates :asset_name, :asset_serial, :asset_type_id, :asset_model, :asset_manuf, :presence => true
        belongs_to :asset_type
    end

I think I have the controller wired up fine, I was having issues before with forms and routes by having a controller called assets which is an issue as a reserved name in Rails 4.x.x so I rebuilt the controller as inventory and call the Asset class from within.

My question is, I the search_form_for field to look at the Asset model's field for asset_name but when I write the view as I've laid out I constantly get that path error.

Is there a way to pass a different path into the Ransack search_field method so that I can get past what seems to be an issue with conventions?

If you need more information or if my question is not clear enough, please do not hesitate to edit or ask for more information. Thanks all!

Posted in CSV Model method and Summing Hours cleanly.

I've made a bit of a mess with my timeclock functionality. Basically what I want to do is pass all of the records in a given search range (which I've already written a model method for and it's working), merge and persist the params into the controller and pass it to a to a to_csv method in the model.

Here's what my controller action looks like with the respond_to block.

def index
    @clock_event = current_user.clock_event
    @user = current_user
    @clock_events = current_user.clock_events.complete.search(params[:search])
      respond_to do |format|
        format.html do
          @clock_events = @clock_events.paginate(:per_page => params[:per_page] || 5, :page => params[:page]).order('created_at DESC')
        end
        format.csv { send_data ClockEvent.to_csv(@clock_events) }
      end

This works fine and dandy, no problems. Now take a look at the model method.

def self.to_csv(records = [], options = {})
    CSV.generate(options) do |csv|
      csv << ["Employee", "Clock-In", "Clock-Out", "Station", "Comment", "Total Shift Hours", "Total Hours: #{TimeFormatter.format_time(records.sum(&:total_hours))}"]
      records.each do |ce|
        csv << [ce.user.try(:username), ce.formatted_clock_in, ce.formatted_clock_out, ce.station.try(:station_name), ce.comment, TimeFormatter.format_time(ce.total_hours)]
      end
    end
  end

Since I was shoveling an array into the csv object I really wasn't sure on where to put the total sum of each clock event to calculate the value. So I made a dirty hack by interpolating the object and putting it into the csv header. Is there a better way to do this where I can have the total sum of records display at the bottom of the CSV file? I'm sure this is simple but I'm just not getting it.

Posted in Code Challenge idea

Sounds great. We should come up with some challenges and get this party started. Chris you want to do the honors or do you want me to write some ridonkulous code :P

When the brainfog clears and the caffeine kicks in, it's go time :)

Ok, I think I figured this out on my own.

The params that were being passed from the form was not [:timecard] but instead was [:clock_event]

So in my create action in the timecards_controller.rb I changed the following to get the right params hash.

def create
    parse_times!
    @clock_event = ClockEvent.new(params[:clock_event])

     if @clock_event.save
       redirect_to timecard_path(@clock_event.user.id), notice: "Entry added for #{@clock_event.user.username}".html_safe
      else
       render :new, notice: "Time Card Entry failed to Save".html_safe
      end
  end

private
  def parse_times!
    params[:clock_event].parse_time_select! :clock_in if params[:clock_event].has_key? 'clock_in(5i)'
    params[:clock_event].parse_time_select! :clock_out if params[:clock_event].has_key? 'clock_out(5i)'
  end

In the form I needed to pass the explicit url and the method of post to get this to work since I'm working with an object outside of the Rails namespace convention

<%= form_for @clock_event, url: "/timecards", method: :post do |ce| %>

Voila... It's working!

Disregard guys...

I'm working on my TimeClock functionality for a legacy Rails 3.2.21 app and am running into problems with simple crud type forms.

I'm trying to create a new ClockEvent entry using a basic form in Rails. When I submit the form I raise an exception in the dev log:

undefined methodclock_events_path' for #<#Class:0x007feadcbbf250:0x007feadcbef298>`

Here is what my code looks like:

new.html.erb

<h4>New TimeCard Entry </h4>
<%= form_for (@clock_event) do |ce| %>
    <%= ce.collection_select(:user_id, User.employee.order("username ASC"), :id, :username, {:include_blank => true}, {:class => 'select', required: true}) %>
    <%= ce.label "Clock In" %>
    <%= ce.date_select :clock_in, order: [:month, :day, :year] %></br>
    <%= ce.time_select :clock_in, :combined => true, :minute_interval => 1, :start_hour => 00, :end_hour => 23 %>
    <%= ce.label "Clock Out" %>
    <%= ce.date_select :clock_out, order: [:month, :day, :year] %></br>
    <%= ce.time_select :clock_out, :combined => true, :minute_interval => 1, :start_hour => 00, :end_hour => 23 %>
    <%= ce.label "Station" %>
    <%= ce.collection_select(:station_id, Station.order("station_name ASC"), :id, :station_name, {:include_blank => true}, {:class => 'select', required: true}) %>

    <%= ce.button  'Create Entry', class: 'btn btn-info', data: {disable_with: "<i class='icon-spinner'></i>Creating..."} %>
<% end %>

timecards_controller

class TimecardsController < ApplicationController

  def index
    @users = User.employee.order("username ASC")
  end

  def new
    @clock_event = ClockEvent.new
  end

  def create
    parse_times!
    @clock_event = ClockEvent.new(params[:timecard])

     if @clock_event.save
       redirect_to clock_event_path, notice: "Entry added for #{@clock_event.user.username}".html_safe
      else
       render :new, notice: "Time Card Entry failed to Save".html_safe
      end
  end

  def show
    @user = User.find(params[:id])
    @clock_events = @user.clock_events.order("created_at ASC").paginate(:per_page => 10, :page => params[:page])
  end

  def edit
    @user = User.find(params[:id])
    @clock_events = @user.clock_events.order("created_at ASC").paginate(:per_page => 10, :page => params[:page])
  end

  def update
    @clock_event = ClockEvent.find(params[:clock_event][:id])
    if @clock_event.update_attributes(params[:clock_event])
        redirect_to edit_timecard_path(@clock_event.user.id), notice: "Updated Successfully".html_safe
    else
        redirect_to :back, notice: "Woops.".html_safe
    end
  end

  private

  def parse_times!
    params[:timecard].parse_time_select! :clock_in if params[:timecard].has_key? 'clock_in(5i)'
    params[:timecard].parse_time_select! :clock_out if params[:timecard].has_key? 'clock_out(5i)'
  end
end

routes.rb

resources :timecards

output of rake routes

 timecards GET    /timecards(.:format)                 timecards#index
                           POST   /timecards(.:format)                 timecards#create
              new_timecard GET    /timecards/new(.:format)             timecards#new
             edit_timecard GET    /timecards/:id/edit(.:format)        timecards#edit
                  timecard GET    /timecards/:id(.:format)             timecards#show
                           PUT    /timecards/:id(.:format)             timecards#update
                           DELETE /timecards/:id(.:format)             timecards#destroy

In my new.html.erb I'm passing the @clock_event object that's defined under the controller's new method. But it keeps giving me the

undefined methodclock_events_path' for #<#Class:0x007feadcbbf250:0x007feadcbef298>` error.

Should I be manually passing a URL path and a method for this since the instance variable does not match the controller convention? And if so, what URL should I be passing?

This seems like I'm making some newb mistakes here but I've had an AirPair expert help me with something similar and we had to do some really ugly passing of URL paths with ID to get it to work.

I'm open to feedback, criticism, and slaps on the back of the head.

Posted in Idea for TimeClock Need Advice

Ok, I spoke to soon. I thought I had this all wired up and the complete scope working. But the !where doesn't work any longer. I had to write the scope as such:

scope :complete, -> { where("clock_out IS NOT NULL") }

Now it scopes properly. I thought I had this working this morning, I could have sworn it was but I just tested it again and it didn't work until I put in the SQL clause into the scope. Rails is not behaving today.

Posted in Idea for TimeClock Need Advice

  scope :incomplete, -> { where(clock_out: nil) }
  scope :complete, -> { where.not(clock_out: nil) }

Note I have these two scopes to parse out incomplete and complete punches. Incomplete works but complete gives a nomethoderror. It appears that the syntax doesn't work at least in this version of Rails. So I rewrote the scope as follows

scope :complete, -> { !where(clock_out: nil) }

So now in my controller I instantiate like so:

  def index
    @clock_event = current_user.clock_event
    @clock_events = current_user.clock_events.complete
  end

In my view I show the total hours like so:

<%= TimeFormatter.format_time(@clock_events.sum(&:total_hours)) %>

This will give a sum of all complete time punches. Works like a champ and gets rid of that screwy number in the view when the array contains an incomplete punch. :)

(Yay for small victories). Now to move on to more useful features and kill my prototype app, merge it into my main app as a feature branch.

Posted in Idea for TimeClock Need Advice

That's a good solution, I was thinking something along those lines but felt at first it was a bit hackish. Would still need some alert or indicator of incomplete punch cycles in the view but I think the scope really makes sense. Thanks for the tip :)

Posted in Idea for TimeClock Need Advice

Well the more I think about it, editing the total is sort of a bad idea. Reason being, if you aren't editing the clock in/out fields you have a chance of skewing the total by editing it manually. Then you have all these time punches that don't jive with the total value.

I pretty much have it working the way I like it with calculating total on the fly with to_i and then parsing in the view with my TimeFormatter class. My main issue right now is when displaying the total hours it shows that screwy negative number when calculating the sum. I need to figure out a way to hide it if there's an incomplete punch (see my pictures above) or somehow calculate all of the punches except the current punch cycle since it's not complete.

Any thoughts on that? I've made great progress with this, but now that it's functional, it's the little things that I need to get a handle on.

Posted in Idea for TimeClock Need Advice

Ping pong... Anyone able to help with this before I go to Stack? Chris? :)

Posted in Code Challenge idea

Chris and I were talking about starting a challenge/kata exercise for the community in Ruby/Rails. Based off of the idea of Underhanded-C, we could post a weekly, bi-weekly, or monthly challenge for all of you to solve. This would be a lot of fun I think and would prove useful as we get different answers on how to solve a Ruby/Rails problem. It would demonstrate everyone's different techniques and code style while providing a way for others to learn. Think of this as a mini-challenge.

I'd like to start threads soon but would like some ideas on different challenges/katas that we could do. Any thoughts on this guys and gals?

So I'm working on a old version of a legacy app Chris and I paired on, trying to refactor some functionality and am hitting a wall.

I currently have some basic paging functionality which creates a "page" (message), and then sends it out to each unit (vehicle) thusly. It's a very simple implementation and works well, but I'm trying to expand it so I can page units within a specific region instead of one by one or all. Here's what my models, views, and controllers look like so far.

unit.rb

class Unit < ActiveRecord::Base
belongs_to :region
end

paging.rb

class Paging < ActiveRecord::Base
  attr_accessible :message, :unit_id, :region_id  
  belongs_to :unit
  attr_accessor :region_id
end

region.rb

class Region < ActiveRecord::Base
  has_many :units
end

pagings_controller.rb (excerpt)

  def index
    @pages = Paging.order('created_at DESC').paginate(:per_page => 5, :page => params[:page])
    @page = Paging.new
  end

def create
    message = params[:paging][:message]

    units = if params[:paging][:unit_id] == "all"
        Unit.active
    else
        [Unit.find(params[:paging][:unit_id])]
    end

    units.each do |unit|

      @page = Paging.new(params[:paging])
      @page.unit_id = unit.id

      if @page.save
        PagingsMailer.paging(unit.incharge, unit, message).deliver
        PagingsMailer.paging(unit.attendant, unit, message).deliver
        send_paging_sms
      end
    end
    @page = Paging.new
    @pages = Paging.limit(5).order('id desc')
    respond_to do |format|
      format.html {redirect_to pagings_path, notice: "Page was successfully sent"}
      format.js {render "index", notice: "Page was successfully sent"}
    end
  end

app/views/pagings/_form.html.erb

<%= form_for(@page) do |f| %>
    <div class="control-group">
        <div class="controls">  
      <%= f.label :message %>
      <%= f.text_area(:message, size: "40x2", :maxlength => 254, placeholder: "Enter your message here", required: true) %>

      <%= f.label 'Unit'%>

      <%= f.select :unit_id, options_for_select(Unit.active.order(:unit_name).map{ |unit| [unit.unit_name, unit.id] } + [["All Units", "all"]]), {}, {:class => 'select'} %>

      <%= f.select :region_id, options_for_select(Region.order(:area).map{ |region| [region.area, region.id]}, {:class => 'select'}) %>
         </div>
        </br>
        <%= f.button  'Send Page', class: 'btn btn-info', data: {disable_with: "<i class='icon-spinner'></i>Sending..."} %>
    </div>
<% end %>

I've already refactored the pagings controller create method to make it cleaner and more DRY, but I'm having a hard time figuring out how to send pages to either a unit, units (all), or units by region.

I'm right in the middle of working on this code so things are not working properly and could use some guidance. As you can see, in the form, I'm mapping the Regions to get the :region_id so that I can pass it into the params of the request to the controller. Since the paging model does not need to populate the region_id per say (not sure if I need this or not) I've set an attr_accessor for :region_id in the paging model.

So two problems I'm facing right now.
In the params request from the form the :region_id does get passed into the request, but once it hits the controller, I'm unsure of how to deal with it. My initial thought was to assign it to a variable like so:

region = Region.find(params[:paging][:region_id])

This will allow me to grab the :region_id and use it within the controller action. From there I should be able to do something like this:

region.units.active #pull all units for the specific region_id and scope off of active from the unit model

This is where I'm stuck. I'm unsure as to how to handle the region variable inside my existing create method to create a new page and page it out to each unit within that region without breaking the existing architecture.

Second, once I do figure out how to do this, I need to figure out in the form how to choose whether or not to select by :unit_id or :region_id so there form does not pass the params to both.

Sorry if this is a bit scattered, but I'd like to discuss how I might be able to do this. If my question is not clear, please let me know and I'll be happy to elaborate and/or add more sample code.

Cheers!

Posted in I'm lost and can't find the way out

So I think what you'd want to do is add a hidden form field for :uuid like so.

<%= f.hidden_field :uuid %>

That way validations can run and errors will be raised.

Posted in I'm lost and can't find the way out

I think Chris touched on this with the hidden field of uuid in your form. That will allow Rails to perform validations on the field and params sent which if there is an error, it will throw it up in the view, which is what you are looking for. If you can output your current version of the form I can show you how to get the errors to show up if you are still having problems. :)

Posted in Idea for TimeClock Need Advice

Anyone have any thoughts on this before I post to the dread StackOverflow? :)

Posted in Must Read / Must Watch

This was a good read, Chris. Thanks for sharing.

Posted in Ransack Scoping issues

Can you post your routes.rb file and the output rake routes ?

Posted in I'm lost and can't find the way out

Also, there's a gem that can help with whitespaces in a a model's field. I've used it before with good success. Attribute_Normalizer. This won't will only handle leading/trailing whitespace with the strip or squish option but it works really well to sanitize your data. I use it in nearly every app I've written where I need to make sure there's no goofy data entry. After installation here's a quick snippet on how I use it in a model:

normalize_attribute :name, address, :with => :squish

Posted in I'm lost and can't find the way out

Chris beat me to the punch, foiled again :)