Im new to Ruby and rails. Im doing a form which updates :owner value in Hardware database. in using custom views name transfer.html.erb. my form code are display bellow.
<%= form_for #hardware, :url => do_transfer_path do |f| %>
this is my custom controller in hardwares_tranfers_controller.rb
def transfer
#hardware = Hardware.find(params[:id])
if current_user.user_lvl == 0
#users = User.order(:user_lvl)
else
#users = User.where(:refer => current_user.id)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #hardwares }
end
end
end
def do_transfer
# transfer_user = User.where(:id => #hardware.owner).email
# TransferLog.create([:user_id => current_user.id, :hardware_id => #hardware.id])
if #hardware.update_attributes(params[:hardware])
format.html { redirect_to users_url, notice: "Hardware was successfully transfer"}
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #hardware.errors, status: :unprocessable_entity }
end
end
and the error I get is
NoMethodError in HardwaresTransfersController#do_transfer
undefined method update_attributes' for nil:NilClass
Aplication Traces
app/controllers/hardwares_transfers_controller.rb:23:indo_transfer'
Parameter
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"vkwKyuS4eviRN1ogrpOcGh1Y5OBNX0wiBzpV8taNkq0=",
"hardware"=>{"owner"=>"3"},
"commit"=>"Transfer Hardware"}
my routes.rb
match "hardwares_transfers/" => "hardwares_transfers#do_transfer" , :as => :do_transfer
get "hardwares_transfers/:id/transfer" => "hardwares_transfers#transfer", :as => :transfer_hardwares
rake routes>
do_transfer /hardwares_transfers(.:format) hardwares_transfers#do_transfer
transfer_hardwares GET /hardwares_transfers/:id/transfer(.:format) hardwares_transfers#transfer
hardwares GET /hardwares(.:format) hardwares#index
POST /hardwares(.:format) hardwares#create
new_hardware GET /hardwares/new(.:format) hardwares#new
edit_hardware GET /hardwares/:id/edit(.:format) hardwares#edit
hardware GET /hardwares/:id(.:format) hardwares#show
PUT /hardwares/:id(.:format) hardwares#update
DELETE /hardwares/:id(.:format) hardwares#destroy
You need
def do_transfer
#hardware = Hardware.find(params[:id])
...
end
I'll also take this opportunity to point out that you could probably frame this in a more REST-ful manner
find hardware item:
def do_transfer
#hardware = Hardware.find(params[:id])
...
end
and change route.rb:
match "hardwares_transfers/:id" => "hardwares_transfers#do_transfer" , :as => :do_transfer
The error is NoMethodError in HardwaresTransfersController#do_transfer
undefined method update_attributes' for nil:NilClass.
As the error says, that Rails is trying to call update_attributes on nil:NilClass, which implies that your #hardware object is nil.
So, you should initialize it by
#hardware = Hardware.find(params[:id])
You should always look at the error and give it a thought as to why this error is there, it'll help you in learning better.
Related
First of all, this is my first experience with ruby. At this moment, I'm creating tests for the a Controller called Exporter in my application. The method of the Controller I want to test is this:
def export_as_json(equipments)
equipments_json = []
equipments.each {|equipment|
equipment_json = {
:id => equipment.id,
:title => equipment.title,
:description => equipment.description,
:category => equipment.category_id
}
equipments_json << equipment_json
}
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
So, when I try to create a request for this method using this:
RSpec.describe ExporterController, type: :controller do
get '/equipments/all', headers: { 'CONTENT_TYPE' => 'application/json' }, format: :json
expect(response.response).to eq(200)
end
inside the exporter_controller_test.rb file I'm receiving this error:
NoMethodError: undefined method `get' for RSpec::ExampleGroups::ExporterController:Class
This is one of the problems pretty much every one runs into at least once ;)
Step 1: Read the error message very carefully
NoMethodError: undefined method 'get' for RSpec::ExampleGroups::ExporterController:Class
Step 2: Remember the wording NoMethodError: undefined method get for RSpec::ExampleGroups::XXX:Class
Step 3: Solve it by making it an actual example
RSpec.describe ExporterController, "#index", type: :controller do
it "should respond with status: 200" do
get '/equipments/all', headers: { 'CONTENT_TYPE' => 'application/json' }, format: :json
expect(response.response).to eq(200)
end
end
You were simply missing the it block.
I know this is not an answer to your question. But, since you mentioned that you're new to ruby, I thought I would point out that your code could be simplified and prettified a bit.
First, you don't need to do equipments_json = [] and then equipments.each. That's what map is for:
def export_as_json(equipments)
equipments_json = equipments.map{|equipment| {
:id => equipment.id,
:title => equipment.title,
:description => equipment.description,
:category => equipment.category_id
}
}
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
Now, that hash you're putting into equipments_json is just a subset of equipment's attributes. So, use slice there to get the attributes you want:
def export_as_json(equipments)
equipments_json = equipments.map{|equipment| equipment.attributes.slice('id','title','description','category_id')}
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
That map line is still a little long, so, maybe put it into a do block (like you had with each):
def export_as_json(equipments)
equipments_json = equipments.map do |equipment|
equipment.attributes.slice('id','title','description','category_id')
end
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
And personally, I like using symbols instead of strings as my keys, so use with_indifferent_access so that you can use symbols:
def export_as_json(equipments)
equipments_json = equipments.map do |equipment|
equipment.attributes.with_indifferent_access.slice(:id, :title, :description, :category_id)
end
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
That line got a little to long again, so I think I would go ahead and wrap it:
def export_as_json(equipments)
equipments_json = equipments.map do |equipment|
equipment.
attributes.
with_indifferent_access.
slice(:id, :title, :description, :category_id)
end
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
Now, there are some different ways to get those attributes you want (e.g., modifying to_json). But, this will get the job done.
Hope that helps and good luck!
PS: I just noticed in your original hash, you're doing:
:category => equipment.category_id
if that's not a typo and you really want category instead of category_id, then you could do something like:
def export_as_json(equipments)
equipments_json = equipments.map do |equipment|
equipment.
attributes.
with_indifferent_access.
slice(:id, :title, :description).
merge!(category: equipment.category_id)
end
respond_to do |format|
format.json { render :json =>equipments_json }
end
end
Also, the convention for hashes is to do title: equipment.title. :title => equipment.title absolutely works, but is not the current convention. This is a style guide for ruby, in case it helps.
I'm testing my project with rspec and now I'm up to the controllers part. I'm testing this method:
def accept
#app = App.find(params[:id])
#invite = Invite.find_by(app: #app.name, receiver: current_dev.id)
#dev = Developer.find(#invite.sender)
#app.developers << #dev
respond_to do |format|
if #invite.destroy
format.html { redirect_to #app, notice: 'A new developer joined your team!' }
format.json { render :show, status: :destroyed, location: #app }
else
format.html { render :back }
format.json { render json: #invite.errors, status: :unprocessable_entity }
end
end
end
and this is the test part:
it "should accept an invite (1)" do
invite = Invite.create(:app => "test", :sender => "2", :receiver => "1")
get :accept, :id => 1
assert_response :success
end
but when I run the rspec command I get this error:
InvitesController should accept an invite (1)
Failure/Error: #dev = Developer.find(#invite.sender)
NoMethodError:
undefined method `sender' for nil:NilClass
So I am assuming that the invite object is nil but I can't figure out why this happens. I test the function via browser and everything works fine. This is also causing same errors in different controller methods, every time just because my invite object is nil. Why is this happening?
SOLVED:
Main reason things weren't working: mismatch between created invite parameters and current parameters (app, current_developer)
Debug: setting breakpoints/printing values of what was needed in the controller and what was needed in the model.
Fixing: created objects that were missing in order to match parameters; correct solution was
it "should accept an invite (1)" do
invite = Invite.create(:app => #app.name, :sender => "2", :receiver => #developer.id)
get :accept, :id => #app.id
assert_response :redirect
end
Can't figure out what's going on as I try to add dirt simple blog capability to my website. Starter app I'm using is pre-configured for HAML and I'm an even bigger HAML n00b than Rails n00b, so I'm seriously struggling.
When I add this to my pages/home.html.haml:
%h1= I18n.t('brand.name')
%p
= I18n.t 'brand.name'
- #posts. each do |post|
= render 'posts/post', post: post
I get:
undefined method `each' for nil:NilClass
I can't figure it out... I thought Ruby had an "each" method built it? Why isn't it passing any class in?
Here's the _post.html.haml partial it's trying to render:
%p
%h2
= link_to post.title, post
%p
- if post.kind == 'image'
= image_tag post.content, style: "width: 100%"
- else
= simple_format post.content
%p.text-muted
%small
Posted on #{post.created_at.to_formatted_s(:long)}
And the controller:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
end
def edit
end
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
else
format.html { render action: 'new' }
end
end
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
else
format.html { render action: 'edit' }
end
end
end
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:title, :kind, :content)
end
end
And the model is empty, just:
class Post < ActiveRecord::Base
end
I copy/pasted most of this code from a working blog example I built in a tutorial and it works fine in that app.
I suspect it has something to do with PSQL (in this app) versus SQLite (in the example app). In rails console, trying it gives the same error:
[3] pry(main)> post = post.first
NoMethodError: undefined method `first' for nil:NilClass
[4] pry(main)> posts = post.each
NoMethodError: undefined method `each' for nil:NilClass
[5] pry(main)> posts = Post.each
NoMethodError: undefined method `each' for Post (call 'Post.connection' to establish a connection):Class
from /Users/troot/.rvm/gems/ruby-2.1.3/gems/activerecord-4.1.6/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
I don't understand why the methods that I think should be working are not working here. Thanks so much for any help you can give.
In this line:
- #posts. each do |post|
there is a space between #posts and each. There should be no space in between as each is a method and you are explicitly calling it using the . operator on #posts object.
Then in console you are doing:
post = post.first
It should be:
post = Post.first
The class name should always be in capital.
And in the console if you need to run each then you need to do Post.all.each you can use each directly on class.
Try correcting this and then check. Hope this helps.
Forgive my ignorance but I am quite new to RoR. I am working on a project where users are able to duplicate a post in order to edit this "cloned version" and to save it (with a new post id, of course).
First I tried to use the Amoeba gem described like here, but I failed.
Then I thought I found a better solution - Duplicating a record in Rails 3 - but when I am integrating the suggested code, I am receiving the following error:
NoMethodError in Posts#show
undefined method `clone_post_path' for #<#:0x0000010267b8c8>
Researching and tinkering for hours now, I would really appreciate any help!
I am using Rails 3.2.13.
In my posts_controller I have the following code:
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
def new
#post = current_user.posts.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
def clone
#post = current_user.posts.find(params[:id]) # find original object
#post = current_user.posts.new(#post.attributes) # initialize duplicate (not saved)
render :new # render same view as "new", but with #post attributes already filled in
end
def create
#post = current_user.posts.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
This is the post.rb model:
class Post < ActiveRecord::Base
attr_accessible :content, :title, :videos, :link, :description
validates :title, presence: true
belongs_to :user
end
In the show view I call this:
<%= link_to 'Create a clone', clone_post_path(#post) %>
What am I doing wrong?
Thank you so much in advance for any help!
UPDATE:
Adding
resources :posts do
get 'clone', on: :member
end
to the routes file worked.
Here is the routes file:
Tt::Application.routes.draw do
devise_for :users
get 'about' => 'pages#about'
resources :posts
root :to => 'pages#home'
post 'attachments' => 'images#create'
resources :posts do
get 'clone', on: :member
end
end
Unfortunately afterwards a new error occurred:
ActiveModel::MassAssignmentSecurity::Error in PostsController#clone
Can't mass-assign protected attributes: id, created_at, updated_at, image_file_name, image_content_type, image_file_size, image_updated_at, file, user_id
Make sure that your routes file includes the following:
resources :posts do
get 'clone', on: :member
end
Since the clone action is not a standard action you must account for it in your routes file so it knows what to do.
I'm building a concert ticket sales application with Rails 3.0.4, working primarily with the Agile Web Development tutorial (http://pragprog.com/titles/rails3/agile-web-development-with-rails) and trying to incorporate Ryan Bate's order purchase method (http://railscasts.com/episodes/146-paypal-express-checkout). Everything works with the following in orders_controller.rb:
def create
#order = Order.new(params[:order])
#order.add_line_items_from_cart(current_cart)
#order.ip_address = request.remote_ip
respond_to do |format|
if #order.save
Notifier.order_received(#order).deliver
format.html { redirect_to(calendar_url, :notice => 'Thank you for your order.') }
format.xml { render :xml => #order, :status => :created, :location => #order }
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
else
format.html { render :action => "new" }
format.xml { render :xml => #order.errors, :status => :unprocessable_entity }
end
end
But when I add "&& #order.purchase" to the conditional clause, with the order.rb model as follows:
class Order < ActiveRecord::Base
#...
belongs_to :cart
#...
def price_in_cents
(cart.total_price*100).round
end
def purchase
response = GATEWAY.purchase(price_in_cents, credit_card, purchase_options)
cart.update_attribute(:purchased_at, Time.now) if response.success?
response.success?
end
#...
end
I receive an "undefined method `total_price' for nil:NilClass" error. I can get around this by adding
#order = current_cart.build_order(params[:order])
to the orders "create" method, but this messes up the "order_received" notification by somehow preventing the pertinent order information (in this case "#order.line_items") from rendering in the e-mail text.
The "cart" object is being set to nil somewhere along the way, but removing
Cart.destroy(session[:cart_id])
from the order "create" method does not fix the problem.
Anyone got a clue for this noob?
It doesn't look like the Cart object is ever actually specified in the belongs_to relation, you need to either do #order.cart = current_cart, or current_cart.order = Order.new, or something along those lines.