Controller 'new' method error - ruby-on-rails

I am following a tutorial
and I am getting an error for my new action. I am using the tutorial as a guideline and my database differs. Here is my code:
def new
#skill = Skill.new
#skills = Skill.find(:all)
end
and here is my error message:
uninitialized constant SkillsController::Skill
#skill = Skill.new is the highlighted line so my mistake should be there somewhere. Thank you and I will keep trying to fix it with the power of research!
^^^^^^^^^^^^^^^solved^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Now I am getting a new error and it seems my database is not quite built right for the skill id's. I am trying to go to localhost:3000/skills/list, Here is my code:
class SkillsController < ApplicationController
def list
#skills = Skill.find(:all)
end
def show
#skills = Skill.find(params[:id])
end
and my error is:
Couldn't find Skill without an ID
and it highlights:
#skills = Skill.find(params[:id])
as the problem area. Thank you for anyone who knows how to solve this issue and also, If I should re-post as a different question let me know and I will do so. Thanks again and huzzah for the web dev community!

Syntax
Firstly, Rails 4 syntax should read as:
def new
#skills = Skill.all
end
--
Error
In regards to your error, as described in the comments, you really need to ensure you have the Skill class available in your application.
You must remember Rails is basically just a series of classes & modules, which means that if you're trying to call a "model", you're essentially calling a Ruby Class which needs to be loaded (as constants).
The problem is your application hasn't got the Skill class (model) loaded. This is most likely the result of not having it in your app/models directory:
#app/models/skill.rb
Class Skill < ActiveRecord::Base
...
end
What concerns me, though, is how your error is trying to wrap this model in another class - SkillsController. This would typically be the case if you've namespaced the controller; but either way you should create the model, restart your server & test again

I think you are messing up with rails conventions. Rails expect Controller class names to be pluralized, such that SkillsController would be the controller class for the skills table. Rails will then look for the class definition in a file called skills_controller.rb in the /app/controllers directory. For more information on naming conventions refer here.
Also since your error says uninitialized constant SkillsController::Skill. I think you don't have your skills table setup with Skill.rb model notice your table name will be plural and your model name will be singular

Related

How does a controller class access a model class?

How does this random controller class
class RandomController < ApplicationController
def index
#user = User.all
end
end
access the User class? I've been searching for the connection in the source files, but I can't seem to find a logical explanation.
Rails has 'constant autoloading', so you don't need to add require 'user' to the top of your file.
http://guides.rubyonrails.org/autoloading_and_reloading_constants.html
When Rails encounters a missing constant, it tries to load a file with a filename based on the constant's name. This nearly always works smoothly... C-;

ActiveResource toplevel constant issue; query path is different intermittently.

Currently I have the above mentioned issue.
From my understanding, this is an on going issue with rails autoloading and how there are standards in namespacing the various class.
Product which retrieve product/products without any scope.
# product.rb
class Product < ActiveResource::Base
self.site = "#{end_point}/api/v2"
....
end
Market::Product which provide us an interface to seek product under the market scope, which is similar to a product.
# market/product.rb
class Market
class Product < ::Product
self.site = "#{end_point}/api/v2/markets/:market_name"
....
end
end
Controller could call the market product object, but the object being return is just product
# market_product_controller.rb
class MarketProductController < ApplicationController
def index
#object = ::Market::Product.all
end
....
end
On api, they are 2 different end-point, with 2 different result sets.
So far, when calling ::Market::Product, it seems like it is using ::Product url and :market_name as a params to that url.
Is there a good solution to this?
How did the rest of the community get around this issue?
Cheers for any help that is given.
Found the answer to my problem.
http://blog.revathskumar.com/2013/12/activeresource-passing-prefix-options.html
It would have seem that I have used activeresource incorrectly all these while.
self.site = end_point
self.prefix = '/api/v2/markets/:market_name/'
This would be the right way to use it when it comes to nested resource.
This solution would work nicely when it gets to ActiveResource::Base.rb:1029. It would be able to get the right prefix_parameters from the prefix_source and then create the right path to the remote end point.
Hope this solution would help others who might encounter the same issue in the future.

How to reassign STI class to a variable within model's method?

I've got STI like this:
class Post
end
class Post::Confirmed < Post
end
class Post::Draft < Post
def confirm!
becomes Post::Confirmed
end
end
...# somewhere in controller
# POST /posts/1/confirm
# POST /posts/1/confirm.json
def confirm
#post = Post::Draft.first
#post = #post.confirm! # this is the only way I can reload #post with Post::Confrmed
end
Is it somehow possible to make:
#post.confirm! # I want this #post(Post::Draft) to become Post::Confirmed without reassigning
Or is it just nor RoR way?
Thanks in advance!
The pattern I've found that works best here is having a datetime type field that records when the record was flagged.
For example:
def confirm!
self.confirmed_at = DateTime.now
self.save!
end
Then you can tell when something was confirmed. This comes in especially handy for when you have a situation where something will be flagged but isn't yet, such as setting a publishing date in the future.
Although it might seem a little annoying to not have your STI bag of tricks available, STI is not always the appropriate tool. Generally STI is to differentiate between similar but different models that have a lot of commonality or are used in a common context. It's not supposed to be used to handle different states of a singular model.
What you want in that case is a state-machine type pattern.

Spree::OrderPopulator accessing outside of store

On Rails 4.1 .. being new to Spree 2-3-stable and experimenting with various things. My test store works fine and now I would am trying and integrate it into my application which is a booking site.
On my Bookings calendar I would like users to click on a booking link and have that auto populate their cart, then show their cart directly.
So assuming I have a spree product, and a variant existing in the database, and the current_user is logged in (ie spree_current_user exists) .. I thought this would be possible but it seems it will not even create the populator.
class BookingsController < ApplicationController
def add_booking_to_cart
populator = Spree::OrderPopulator.new Spree::Order.current_order(create_order_if_necessary: true), current_currency
# .. get variant related to booking
# .. add varient to populator
end
#... rest of bookings controller
end
Errors out with:
NoMethodError - undefined method `current_order' for #<Class:0x00000007d4fc68>:
I am attempting to do a similar thing to what Will is doing here but am getting the error undefined method on current_order object. My understanding of the code is that it should create a new order if necessary, ie if one does not exist. No sure what do to here? Any pointer would be greatly aprecieated.
https://github.com/spree/spree/blob/2-3-stable/frontend/app/controllers/spree/orders_controller.rb#L46
For this to work your controller needs to extend Spree::StoreController
class BookingController < Spree::StoreController
This is where the method is defined in Spree:
https://github.com/spree/spree/blob/master/core/lib/spree/core/controller_helpers/order.rb
Also, you might need to have a before_filter :set_current_order.

Rails refactoring: Where would you put hash which maps one table's fields to another

So, I have a database of people on an external system, and I want to set up the code to easily create people records internal to our sysem based on the external system. The field names, of course, are not the same, so I've written some code which maps from one table to the next.
class PeopleController < ApplicationController
...
def new
#person = Person.new
if params[:external_id] then
initialize_from_external_database params[:external_id]
end
end
private
def initialize_form_external_database(external_id)
external = External::Person.find(external_id)
if external.nil?
...
else
#person.name_last = exteral.last_name
#person.name_first = external.first_name
#...
#person.valid?
end
end
end
Okay, so the stuff in the "else" statement I can write as a loop, which would use a hash something like:
FieldMappings = {
:name_last => :last_name,
:name_first => :first_name,
:calculated_field => lambda {|external_person| ... },
...
}
But where would you put this hash? Is it natural to put it in the External::Person class because the only reason we access those records is to do this initialization? Or would it go in the controller? Or a helper?
Added: Using Rails 2.3.5.
I'd put this code in the External::Person to avoid Person even having to know it exists. Use a 'to_person' method (or maybe 'to_internal_person') on External::Person. Keep the Hash in External::Person and use it to perform the generation. Either way as JacobM says, you want this code in your model, not controller.
class PeopleController < ApplicationController
def new
if external = External::Person.find_by_id params[:external_id]
#person = external.to_person
else
#person = Person.new
end
end
end
If you're in Rails 3.x (maybe also in 2.x, I'm not sure), you can put miscellaneous classes and modules in your /extras folder which is included in the autoloader path. This is where I always put things of this nature, but I' not aware of any Rails convention for this sort of thing.
First of all, I would do that work in your (internal) Person model -- give it a class method like create_person_from_external_person that takes the external person and does the assignments.
Given that, I think it would be OK to include the hash within that Person model, or somewhere else, as Josh suggests. What would be particularly cool would be to write a generic create_person_from_external_person method that would ask the external person for a hash and then do the mapping based on that hash; that approach could support more than one type of external person. But that may be overkill if you know this is the only type you have to deal with.
I wouldn't put it in the controller, but, again, I wouldn't do that work in the controller either.
You can put it on a module on the lib directory so you don't mess any of your classes that will be full of awesome code that will probably last many years. Another good reason is you can then include/require your mapping module everywhere you need it (maybe in your tests).
module UserMapping
FIELDS = { :last_name => :name_last, .... }
end
If you drop the module on the lib and you use rails 3 you should put this on your config/application.rb file:
config.autoload_paths += %W(#{config.root}/lib)
On Rails::VERSION::MAJOR < 3 the lib directory is automatically added to the autoload_path

Resources