Get variable from Controller to Model - ruby-on-rails

I'm trying to get a variable from the controller over to the model. Its the value of a checkbox passed up from the View. I cant see it in the controller (0 or 1) and just need to get it to the model. I have seen tons of examples on here but none of them seem to work for me. Maybe its something about the Ruby environment we have setup? Its a Rails 5 environment.
Here is what I have tried so far and the errors it gives in the logs:
Controller:
#vin = Vehicle.create!
#results = #vin.myvin!(params[:vehicle][:vincheck])
Model:
def myvin!(localvin)
logger.info "MADE IT INTO VIN"
end
Error in development.log:
AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action.
I'm not calling render or redirect!! Just trying to call the method in the model.
I have also tried a variation like:
Controller:
Vehicle.myvin(params[:vehicle][:vincheck])
Model:
def self.myvin(localvin)
logger.info "MADE IT INTO VIN"
end
But regardless... I always get that render error in the logs!
I have tried instantiating a new object:
Controller:
Vehicle.new(params[:vehicle][:vincheck])
Model:
attr_reader :localvin
def initialize(localvin)
logger.info "MADE IT INTO VIN"
end
When I do that I get:
500wrong number of arguments (given 0, expected 1)
Short Stack
app/models/vehicle.rb:25:in 'initialize'
app/controllers/vehicles_controller.rb:84:in 'new'
Anyone have any thoughts on how I can get this data over? Maybe it has something to do with the Vehicle Model itself? In the controller it gets instantiated at different places.
For example:
def index
#vehicles = Vehicle.active
end
def create
#this is where I am putting all my code
#not really sure how this is getting created since there was no
#initialize in the code before I added one
#vehicle = Vehicle.new(vehicle_params.merge(
created_by_id: current_user.id,
created_by_name: current_user.name,
deleted: false))
end
thanks!

Related

Unsplash object method available from the console but not from the view

This one baffles me. I've banged my head on it for a couple of weeks now and am getting nowhere. Sorry if it's obvious, I'm still a rails newbie ish...
The app is making an API call to the Unsplash pictures service.
As such the application_helper has the following method:
def show_photo(size)
#photo = Unsplash::Photo.random(query:"cars")[:urls][size.to_sym]
end
the view has the following:
<%= image_tag(show_photo('small'), height: "220", width:"220") %>
And that displays fine.
The issue is when I want to pull some other methods from the oject. I've added another method in the application helped like this:
def show_author
#photo.user.name
end
and the corresponding view:
Photo by: <%= show_author %>
I then get this error:
undefined method `user' for #
However when calling the method in the Rails console it works fine:
#photo = Unsplash::Photo.random(query:"cars")
=> #<Unsplash::Photo:0x00000004fcf950 #attributes=#<OpenStruct id="CKeoh-
90U3E", created_at="2017 .......
2.3.0 :003 > #photo.user.name
=> "Florian Schneider"
What do I need to do to have the user.name available in the view?
Thanks a lot in advance,
Rodolphe
#photo is not the photo, it looks like you're calling some meta-data on #photo with [:urls][size.to_sym] and you can't call .user on top of that meta-data.
You're essentially saying Unsplash::Photo.random(query:"cars")[:urls][size.to_sym].user
You might want to do the following:
def photo
#photo ||= Unsplash::Photo.random(query:"cars")
end
def resized_photo(size)
photo[:urls][size.to_sym]
end
def photo_author_name
photo.user.name
end
btw #photo ||= is memoizing the API call so you're not making the same call multiple times.

Undefined method in controller - rails

I have a controller called blogger:
class BloggerController < ApplicationController
def home
end
def favoritePosts
#blogger = current_blogger
#favorites = #blogger.favorite_posts
end
def suggestedPosts
posts = Post.all
#suggestedPosts = posts.similar_posts
end
end
And in the Blogger model i have a method:
def similar_posts
title_keywords = Post.body.split(' ')
Post.all.sort do |post1, post2|
post1_title_intersection = post2.body.split(' ') & title_keywords
post2_title_intersection = post2.body.split(' ') & title_keywords
post2_title_intersection.length <=> post1_title_intersection.length
end
end
When i run the server its gives me an error:
undefined method `similar_posts' for #<Post::ActiveRecord_Relation:0x007fa365029760>
After searching on stackoverflow i tried def self.similar_postsbut it still gives the same error message. I also tried new in the controller like this #suggestedPosts = posts.new.similar_posts which still gives me the same error.
Any suggestions on how to overcome this?
You have 2 issues happening at the same time. The first is that you're using posts in your call, when you should be using something more like post.blogger. The specific object depends on what your intent actually is.
The second issue is that you're making the call to similar_posts on the association, not on an individual record. This can be resolved with a call to each on the association.
So, putting those together and looking at what you might have meant, I think that you might have intended this as your suggestedPosts method:
def suggestedPosts
posts = Post.all
#suggestedPosts = posts.map {|post| post.blogger.similar_posts }
end
I also changed the name of #suggestedDevelopers to #suggestedPosts, because I don't think that you meant 'developers' in this case. This should give you something closer to what it appear you were trying for.

NoMethodError in Rails while saving data

Checks_controller
class Checkscontroller < ApplicationController
def show
#check= Tester.find(params[:id])
end
def new
end
def create
#check = Tester.new(check_params)
#check.save
redirect_to #check
end
def check_params
params.require(:check).permit(:title, :description)
end
end
I am trying to save the data in 'checks' controller to 'Tester' model, getting "NoMethodError in ChecksController#create", undefined method tester_url' for#` while trying to save the data to my DB. There seems to be some issue on this line: "redirect_to #check".
Routes.rb
Rails.application.routes.draw do
get 'home/screen'
resources :checks
root 'home#screen'
end
EDIT: I see this answer got accepted. To anyone else looking at this: PLEASE DO NOT DO THIS WITHOUT A REALLY GOOD REASON.
Ok, so since you want to use the ChecksController for your Tester model, you'll have to add this to your routes: note that I'm assuming that you do not have a Check model, since I don't see it anywhere and youre using Tester as a check?
resources :testers, as: 'checks' controller: 'checks'
This line will make it so that /checks/1 goes to a Tester object with ID: 1, and use the ChecksController show method to show it
Old answer, for posterity
You're getting this error because you're missing routes for your Tester model in your routes.rb file.
You could add resources :testers to it and it will work. Of course you also already need AT LEAST your TestersController to exist with a show action
This error is occurring because when you redirect_to #check, Rails knows it's a Tester object and expects a route called tester to route to TestersController#show. It's attempting to use a helper method that rails creates for routes, called tester_url

Rails building multiple relationships in one form

Newbie on Ruby here, I've successfully build an html form in which users' "project" models can "follow" (or as I've phrased it "pfollow") other "plant" models. The only problem is that the code I've built doesn't work when users try to "pfollow" multiple plants on one form, which forces the user to hit "submit" multiple times for more plants. If the user selects more than one plant from a selection box at a time, my "project" model and my "prelationship" controller choke on the input, which comes as an array rather than the expected single integer (aka, the "pfollower_id" from the plant which is used by the "prelationships" controller for its create action).
How can I teach my app to accept an array of "pfollower_id(s)" and then create multiple plant prelationships?
Here is the error:
undefined method `id' for #<Array:0x26abe70>
app/models/project.rb:35:in `pfollow!'
app/controllers/prelationships_controller.rb:6:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"NKqa1f0M2yPLQDHbRLnxl3SiwBeTus/1q1hpZjD7hgY=",
"prelationship"=>{"pfollower_id"=>["4",
"5"]},
"project_id"=>"90",
"commit"=>"Pfollow"}
My "prelationships" controller:
class PrelationshipsController < ApplicationController
def create
#project = Project.find(params[:project_id])
#plant = Plant.find(params[:prelationship][:pfollower_id])
#project.pfollow!(#plant)
respond_to do |format|
format.html { redirect_to #project }
format.js
end
end
end
And the suspect "pfollow!" method in my model that the trace indicates is also culpable:
def pfollow!(pfollowed)
prelationships.create!(:pfollowed_id => pfollowed.id)
end
The form works fine, so it's just this controller and method that can't handle an array of pfollower_ids.
I'm desperate for help! Any and all direction would be immensely helpful.
Break it down with an each method in your controller :D
params[:prelationship][:pfollower_id].each do |p|
#project.pfollow!( Plant.find(p) )
end
I'm guessing this would work if only one param is returned as well. Not entirely sure.

How can I pass objects from one controller to another in rails?

I have been trying to get my head around render_to but I haven't had much success.
Essentially I have controller methods:
def first
#I want to get the value of VAR1 here
end
def second
VAR1 = ["Hello", "Goodbye"]
render_to ??
end
What I can't figure out is how to accomplish that. Originally I just wanted to render the first.html.erb file but that didn't seem to work either.
Thanks
Edit: I appreciate the answers I have received, however all of them tend to avoid using the render method or redirect_to. Is it basically the case then that a you cannot pass variables from controller to controller? I have to think that there is some way but I can't seem to find it.
It is not a good idea to assign the object to a constant. True this is in a global space, but it is global for everyone so any other user going to this request will get this object. There are a few solutions to this.
I am assuming you have a multi-step form you are going through. In that case you can pass the set attributes as hidden fields.
<%= f.hidden_field :name %>
If there are a lot of fields this can be tedious so you may want to loop through the params[...] hash or column_names method to determine which attributes to pass.
Alternatively you can store attributes in the session.
def first
#item = Item.new(params[:item])
session[:item_attributes] = #item.attributes
end
def second
#item = Item.new(session[:item_attributes])
#item.attributes = params[:item]
end
Thirdly, as Paul Keeble mentioned you can save the model to the database but mark it as incomplete. You may want to use a state machine for this.
Finally, you may want to take a look at the Acts As Wizard plugin.
I usually don't have my controllers calling each other's actions. If you have an identifier that starts with a capital letter, in Ruby that is a constant. If you want to an instance level variable, have it start with #.
#var1 = ["Hello", "Goodbye"]
Can you explain what your goal is?
Have you considered using the flash hash? A lot of people use it solely for error messages and the like, it's explicitly for the sort of transient data passing you might be interested in.
Basically, the flash method returns a hash. Any value you assign to a key in the hash will be available to the next action, but then it's gone. So:
def first
flash[:var] = ["hello", "goodbye"]
redirect_to :action => :second
end
def second
#hello = flash[:var].first
end
way 1
Global variable
(fail during concurrent requests)
way 2
class variable
(fail during concurrent requests)
way 3
Stash the object on the server between requests. The typical way is to save it in the session, since it automatically serializes/deserializes the object for you.
Serialize the object and include it in the form somewhere, and
deserialize it from the parameters in the next request. so you can store attributes in the session.
def first
#item = Item.new(params[:item])
session[:item_attributes] = #item.attributes
end
def second
#item = Item.new(session[:item_attributes])
#item.attributes = params[:item]
end
way 4
The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed to the very next action and then cleared out.
def new
#test_suite_run = TestSuiteRun.new
#tests = Test.find(:all, :conditions => { :test_suite_id => params[:number] })
flash[:someval] = params[:number]
end
def create
#test_suite_run = TestSuiteRun.new(params[:test_suite_run])
#tests = Test.find(:all, :conditions => { :test_suite_id => flash[:someval] })
end
way 5
you can use rails cache.
Rails.cache.write("list",[1,2,3])
Rails.cache.read("list")
But what happens when different sessions have different values?
Unless you ensure the uniqueness of the list name across the session this solution will fail during concurrent requests
way 6
In one action store the value in db table based on the session id and other action can retrieve it from db based on session id.
way 7
class BarsController < UsersController
before_filter :init_foo_list
def method1
render :method2
end
def method2
#foo_list.each do | item|
# do something
end
end
def init_foo_list
#foo_list ||= ['Money', 'Animals', 'Ummagumma']
end
end
way 8
From action sent to view and again from view sent to other actions in controller.

Resources