Issue with HomeController showing undefined method - ruby-on-rails

I am trying to pass stored_products from shopify into a Rails app but keep getting a home controller error at https://f588240c.ngrok.io/ i have made updates, with no luck and restarted the server a number of times with no luck.
Any help would be welcomed. Heres the code
class Api::V1::HomeController < ShopifyApp::AuthenticatedController
def index
#products = ShopifyAPI::Product.find(:all, params: { limit: 10 })
#products.each do |product|
StoredProduct.where(shopify_id: product.id)
.first_or_create do |stored_product|
stored_product.shopify_id = product.id
stored_product.shopify_title = product.title
stored_product.shopify_handle = product.handle
stored_product.shopify_image_url = product.image.src
stored_product.shop_id = #shop.id
stored_product.save
product.images.each do |image|
ProductImage.where(shopify_id: image.id)
.first_or_create do |product_image|
product_image.image_url = image.src
product_image.stored_product_id = stored_product_id
product_image.shopify_id = image.id
end
end
end
end
#stored_products = StoredProduct.belongs_to_shop(#shop.id)
end
end
From the authenticated controller
private
def set_shop
#shop = Shop.find_by(id: session[:shopify])
set_locale
end
from the store_products.rb file
class StoredProduct < ApplicationRecord
belongs_to :shop
has_many :product_images
scope :belongs_to_shop, -> shop_id { where(shop_id: shop_id) }
end

For this specific issue/code tutorial, the private set_shop method should be set like follows:
def set_shop
#shop = Shop.find_by(id: session[:shop_id])
set_locale
end
The other answer has params instead of session

The problem is that #shop is nil. The error message says it cannot call the method .id on NilClass.
In the image I can see that you have a shop_id in the params so you might just need to change your code here:
def set_shop
#shop = Shop.find_by(id: params[:shop_id])
set_locale
end
But that depends on your code, so please double check.

Related

How to set karma to appropriate user

I'm trying to add a user karma feature to my app and I'm almost done, just that the karma is being awarded to a different user.
NB, My like system is from scratch and not acts_as_votable.
What I want:
When a user upvotes a book, I want a +1 karma be awarded to the
book.user
If a user's books are downvoted more then they upvoted, I want such
user have negative karma.
What I'm getting:
When a book is upvoted, the user who upvoted the book gets the +1
karma instead of the book.user.
When a user with 0 karma gets his/her book downvoted, the karma incrment by 1 instead of decrementing.
class AddKarmaToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :karma, :integer, default: 0
end
end
My code:
vote.rb
class Vote < ApplicationRecord
belongs_to :user
belongs_to :book
validates_uniqueness_of :user_id, scope: :book_id
after_create :increment_vote, :add_karma
after_destroy :decrement_vote, :remove_karma
private
def increment_vote
field = self.upvote ? :upvotes : :downvotes
Book.find(self.book_id).increment(field).save
end
def decrement_vote
field = self.upvote ? :upvotes : :downvotes
Book.find(self.book_id).decrement(field).save
end
def add_karma
user = User.find(self.user_id)
user.increment(:karma, 1).save
end
def remove_karma
user = User.find(self.user_id)
user.decrement(:karma, 1).save
end
end
votes_controller.rb
class VotesController < ApplicationController
def create
book_id = params[:book_id]
vote = Vote.new
vote.book_id = params[:book_id]
vote.upvote = params[:upvote]
vote.user_id = current_user.id
#check if vote by this user exists
existing_vote = Vote.where(user_id: current_user.id, book_id: book_id)
#new_vote = existing_vote.size < 1
respond_to do |format|
format.js {
if existing_vote.size > 0
#destroy existing vote
existing_vote.first.destroy
else
#save new vote
if vote.save
#success = true
else
#success = false
end
# #total_upvotes = #book.upvotes
# #total_downvotes = #book.downvotes
end
#book = Book.find(book_id)
#is_upvote = params[:upvote]
render "votes/create"
}
end
end
private
def vote_params
params.require(:vote).permit(:upvote, :book_id)
end
end
First of all when using active record relations you don't need to call Model.find in the class, just call the relation with it's name:
def increment_vote
field = self.upvote ? :upvotes : :downvotes
book.increment(field).save
end
def add_karma
user.increment(:karma, 1).save
end
In add_karma and remove_karma you are referencing the user that the vote belongs to, and not the user that owns the book. To achieve your goal you should also increment and decrement karma on the book's owner:
def add_karma
user.increment(:karma, 1).save
book.user.increment(:karma, self.upvote ? 1 : -1).save
end
def remove_karma
user.increment(:karma, 1).save
book.user.decrement(:karma, 1).save
end
You could rewrite your controller to simplify the code:
class VotesController < ApplicationController
def create
#vote = current_user.votes.find_or_initialize_by vote_params[:book_id]
#vote.assign_attributes vote_params
#success = #vote.save
# instead of #book = #vote.book just use #vote.book in your view
#book = #vote.book
# instead of #is_upvote you can use #vote.upvote in your view
#is_upvote = #vote.upvote
respond_to do |format|
format.js { render 'votes/create'}
end
end
private
def vote_params
params.require(:vote).permit(:upvote, :book_id)
end
end

dup or clone action in rails

Well im going to clarify im doing it
class DuplicatesController < ApplicationController
before_action :set_venue, only: [:new]
def new
end
def create
if #venue.duplicate(venue_params)
flash[:success] = t('controller.create.success',
resource: Venue.model_name.human)
redirect_to admin_venue_url #venue
else
flash[:warning] = #venue.errors.full_messages.to_sentence
render :new
end
end
private
def set_venue
#venue = Venue.friendly.find params[:venue_id]
end
end
def venue_params
params.require(:venue).permit(:name,
:address,
:address_complement,
:city,
:phone)
end
end
def duplicate
(name,
address,
address_complement,
city,
phone)
new_venue = self.dup
new_venue.update_attributes(description: self.description,
logo: self.logo,
opening_time: self.opening_time,
closing_time: self.closing_time,
ally_id: self.ally_id)
new_venue.save
end
How can I call those params in my duplicates controller, thanks
I need to set the attributes, after create a dup because I want to save a new record with new information, but i dont know to do it in my method, someone could explain me
Thanks.
Probably the best way to do it is to pass only id/slug of original model.
Then your duplicates_controller.rb can look similar to this:
class DuplicatesController < ApplicationController
def create
old_venue = Venue.friendly.find(params[:id])
venue = old_venue.dup
venue.attributes = venue_params
if venue.save
# success render
else
# error render
end
end
private
def venue_params
params.require(:venue).permit(:permitted_attributes) # id should not be there
end
end
Of course you can refactor it, but I do not think it is needed in this situation.
Or my favourite is to change VenueController#create to something like this to allow creating from another instance:
if copy_from_id = params[:copy_from_id]
#copy_source = Venue.find_by(id: copy_from_id)
#venue = #copy_source.dup
#venue.attributes = venue_params
else
#venue = Venue.new
end
if #resource.save
...
else
...
end

Rails class method not defined

I have a controller which calls a class method from a model. However, I got undefined method 'where' for Jira:Class.
controller:
module Api
module V1
class JiraController < ApplicationController
def index
jira = Jira.where()
jira_stat = JiraStat.new(jira)
render json: [
{
t('jira.api.status') => jira_stat.status,
t('jira.api.number_of_jiras') => jira_stat.jira_total
}
]
end
end
end
end
model:
# frozen_string_literal: true
require 'active_model'
class Jira
include ActiveModel::Model
include JiraKit
attr_accessor :status, :jira
def self.where(status_name = 'all')
if status_name == 'all'
jiras = JiraKit.where.jira_issues(status: ['open', 'submitted', 'in
progress', 'in review', 'closed'])
elsif
jiras = JiraKit.where.jira_issues(status: [status_name])
end
new(#status = status_name, #jira = jiras)
end
end
I think I have used self keyword. But I don't know why I can't access that method. If I create an instance of Jira model, I am able to access that method.

undefined method `map' api request [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I followed tutorial how to integrate 3rd party api with a ruby on rails but I get an error
undefined method `map' for
{"number"=>12} permitted: false>:ActionController::Parameters
which points to request.rb
query_string = query.map{|k,v| "#{k}=#{v}"}.join("&")
Full code
recipes_controller.rb
class RecipesController < ApplicationController
def index
#tag = query.fetch(:tags, 'all')
#refresh_params = refresh_params
#recipes, #errors = Spoonacular::Recipe.random(query, clear_cache)
end
def show
#recipe = Spoonacular::Recipe.find(params[:id])
end
private
def query
params.permit(:query).fetch(:query, {})
end
def clear_cache
params[:clear_cache].present?
end
def refresh_params
refresh = { clear_cache: true }
refresh.merge!({ query: query }) if query.present?
refresh
end
end
app/services/spoonacular/recipes.rb
module Spoonacular
class Recipe < Base
attr_accessor :aggregate_likes,
:dairy_free,
:gluten_free,
:id,
:image,
:ingredients,
:instructions,
:ready_in_minutes,
:title,
:vegan,
:vegetarian
MAX_LIMIT = 12
CACHE_DEFAULTS = { expires_in: 7.days, force: false }
def self.random(query = {}, clear_cache)
cache = CACHE_DEFAULTS.merge({ force: clear_cache })
response = Spoonacular::Request.where('recipes/random', cache, query.merge({ number: MAX_LIMIT }))
recipes = response.fetch('recipes', []).map { |recipe| Recipe.new(recipe) }
[ recipes, response[:errors] ]
end
def self.find(id)
response = Spoonacular::Request.get("recipes/#{id}/information", CACHE_DEFAULTS)
Recipe.new(response)
end
def initialize(args = {})
super(args)
self.ingredients = parse_ingredients(args)
self.instructions = parse_instructions(args)
end
def parse_ingredients(args = {})
args.fetch("extendedIngredients", []).map { |ingredient| Ingredient.new(ingredient) }
end
def parse_instructions(args = {})
instructions = args.fetch("analyzedInstructions", [])
if instructions.present?
steps = instructions.first.fetch("steps", [])
steps.map { |instruction| Instruction.new(instruction) }
else
[]
end
end
end
end
app/services/spoonacular/base.rb
module Spoonacular
class Base
attr_accessor :errors
def initialize(args = {})
args.each do |name, value|
attr_name = name.to_s.underscore
send("#{attr_name}=", value) if respond_to?("#{attr_name}=")
end
end
end
end
app/services/spoonacular/request.rb
module Spoonacular
class Request
class << self
def where(resource_path, cache, query = {}, options = {})
response, status = get_json(resource_path, cache, query)
status == 200 ? response : errors(response)
end
def get(id, cache)
response, status = get_json(id, cache)
status == 200 ? response : errors(response)
end
def errors(response)
error = { errors: { status: response["status"], message: response["message"] } }
response.merge(error)
end
def get_json(root_path, cache, query = {})
query_string = query.map{|k,v| "#{k}=#{v}"}.join("&")
path = query.empty?? root_path : "#{root_path}?#{query_string}"
response = Rails.cache.fetch(path, expires_in: cache[:expires_in], force: cache[:force]) do
api.get(path)
end
[JSON.parse(response.body), response.status]
end
def api
Connection.api
end
end
end
end
app/services/spoonacular/connection.rb
require 'faraday'
require 'json'
module Spoonacular
class Connection
BASE = 'https://spoonacular-recipe-food-nutrition-v1.p.mashape.com'
def self.api
Faraday.new(url: BASE) do |faraday|
faraday.response :logger
faraday.adapter Faraday.default_adapter
faraday.headers['Content-Type'] = 'application/json'
faraday.headers['X-Mashape-Key'] ='key'
end
end
end
end
Thank you for any help.
You have 2 separate errors here.
uninitialized constant Spoonacular::Recipe::Request
This one you can fix by explicitly setting top-level scope for Request class:
::Request.where(...)
It applies if you keep Request file in app/spoonacular/request.rb. But I suggest to move it to app/services/spoonacular/ where all your other spoonacular related classes are. So in this case you need to encircle class Request in module Spoonacular. After that you can call it like that:
Spoonacular::Request.where(...)
Same goes for class Connection.
SO answer about scope resolution operator
undefined method `map' for {"number"=>12} permitted:
false>:ActionController::Parameters
This one comes from private query method in recipes_controller.rb. params is ActionController::Parameters object and in order to retrieve values from it you need to permit them first:
def query
params.permit(:query).to_h
end
Now it should return Hash object.
Here is detailed answer on SO about that
RubyOnRails Guide about strong params

Rails - Object values not being accessible on a attribute writer method

I have a Study model which have many fields, but I'm having troubles with 1
profesion_name
so in my study model I have this
class Study < ActiveRecord::Base
attr_accessible :profesion_related, :profesion_name
attr_accessor :profesion_related
def profesion_related=(id)
if id.present?
if self.study_type_id == 4
if self.country_id == 170
#some code here
else
profesion_parent = Profesion.find(id)
new_profesion = Profesion.create({g_code: profesion_parent.g_code, mg_code: profesion_parent.mg_code, name: self.profesion_name})
self.profesion = new_profesion
end
end
end
end
end
but I'm getting an error on the line that create a Profesion, because self.profesion_name is nil
if in my controller I do this
def create
#study = Study.new(params[:study])
respond_to do |format|
#here
puts #study.to_yaml
if #study.save
.....
end
I will see in the console that profesion_name has a value
but if I do this
class Study < ActiveRecord::Base
...
def profesion_related=(id)
puts self.to_yaml
....
end
end
I can see that self.profesion_name is empty
Why could this be happening?

Resources