I have tried and tried to find the answer elsewhere, but I just cannot resolve this problem.
I have a model call BidSignal that is related to a model called BuySignal. A BuySignal has many BidSignals and a BidSignal belongs to a BuySignal.
When I create a new BidSignal using the new method in the BidSignal controller I want to capture the BuySignal that it relates to, so I can save the relation in the BidSignal create method. I'm currently doing this by passing the buysignal_id to BidSignal controller on a call to the new method. But when I come to create the BidSignal record and try to recall the buysignal_id to find the BuySignal record, I get an error - Couldn't find Buysignal without an ID
Bid Signal New Method
def new
#buy_signal_idx = params[:buysignal_id]
#bid_signal = BidSignal.new
end
Bid Signal Create Method
def create
#a_buysignal = Buysignal.all
#a_buysignal = #a_buysignal.find(#buy_signal_idx)
#a_bid_signal = #a_buysignal.bid_signals.build(bid_signal_params)
if #a_bid_signal.save
flash[:success] = "Bid Signal Successfully Created!"
redirect_to #a_bid_signal
else
render action: 'new'
end
end
However, if I replace:
#a_buysignal = #a_buysignal.find(#buy_signal_idx)
with:
#a_buysignal = #a_buysignal.find(300)
It all works fine ( except of course all my bid signals are being related to buy signal with id 300 ).
It's as if the #buy_signal_idx is not accessible within the create method. I have tried abstracting this out so that new calls a class to set a variable for the bid signal through it's own new method and then use a getter to return the buy_signal_idx in the bid signal create method. But i get the same result.
I think I get that if I initiate an instance variable in a method that variable should be accessible by other methods in that object instance - but it's not working.
I know i'm being stupid and missing something fundamental - but what is it ?
Every time new request comes in, rails instantiate new instance of the controller class - hence the instance variables set in previous request are no longer available (controller object holding this variable is destroyed by now). This is a result of web being stateless - the only ways to preserve any form of data between two separate requests is to store it within the session or to send it with every request (not really storing the variable, but you know what I mean)
The best choice depends really on your routes here. If you are using nested resources, than params[:buysignal_id] is passed as a part of url (not the query string) and hence it is also accessible within your create action. So you can simply do:
# create action
#a_buysignal = Buysignal.find(params[:buysignal_id])
If it is part of a query string, then I would do:
# new action
#buy_signal_idx = session[:byusignal_id] = params[:buysignal_id]
# create action
#a_buysignal = Buysignal.find(session[:buysignal_id])
Another solution is to add a hidden field with a params[:buysignal_id] value to your form and use it in your create action, but i think it is a little bit cumbersome.
Related
Hello people. I'm creating a log process in my Rails 5 application, inside the application controller. I'm creating there because I want to call the log process inside many controllers with a before_save property. The log will save the changes that user performs in the form on edit view template. The problem is that I can't get the <ObjectController:> inside application controller. I've already got the instance variable from the controller, but I need the ObjectController too, because I have to get the strong parameters from controller object. The strong parameters holds all data that user inserted on input fields.
This is what I've done already:
app/controllers/application controller
def log
#controlr = instance_variable_get("##{controller_name.singularize}") #get the edited object
attribs = #controlr.attribute_names #get object table column names
edited_data = controlr_params #stuck here!
ctrlr = #controlr.attributes #retrive object data from db
...
##compare the edited_data with the actual data from db and check if something was changed
end
So, I need to obtain the Controller Object to access the strong parameters in order to compare if user edited any data. I'm not sure if this is the best way/practice to do this. If there is a better way, I'd like to know. But I need to call this process in a great number of controllers that require a data log.
Thanks for you time and sorry any bad english..
If params method won't help you to achieve your goal (but it's worth to try) you can always access current instance of controller object by calling self in context of any instance method or action.
To test you can put byebug in any action, call that action in browser with additional parameters and type self in console.
For example, in controller:
class UsersController < ApplicationController
def show
byebug
end
end
in browser:
localhost:3000/?some_param=1234&another_param=testing
There will be a lot of useful stuff in there, like self.instance_variables => [.... :#_request, ... :#_params].
Also request method contain all info about current request including parameters.
Hope that'll help.
This is a fairly simple question.
Is there a specific method for updating properties for relationships in the gem? I can't seem to do a simple update_attributes or update.
My relationship is created and update is undefined for nil class.
event = Event.find(params[:event])
invite = Invite.create_invitation(event, current_user, nil) #creates relationship
invite.update(interested: params[:interest])
Is there another method that I should be using?
Whenever you get an error about undefined for nil class, it should be an immediate signal to you that the problem is the variable on which you're calling the method, not the method you're calling. In other words, since it's saying that nil does not have an update method, your focus should be on the variable that is actually nil. The question here: why is invite returning nil instead of a relationship?
Since you're using a custom class method to create the relationship, I'm guessing that you're not telling it to return the right object. It should look something like this:
def self.create_invitation(event, user, something_else = nil)
rel = InvitationRel.new(from_node: event, to_node: user)
if rel.save
rel
else
# return an error, maybe rel.errors.full_messages?
end
end
Then your controller needs to check that the rel was actually created correctly.
event = Event.find(params[:event])
invite = Invite.create_invitation(event, current_user, nil) #creates relationship
if invite.neo_id.nil?
# the rel did not create correctly, neo_id is only present on persisted objects
else
invite.update(interested: params[:interest])
end
This feels to me like you're taking a long way around this problem. You don't need to separate the creation of the relationship and setting the interested property, you can just do it in one call to the DB:
event = Event.find(params[:event])
invite = InviteRel.new(from_node: event, to_node: current_user, interested: params[:interest])
if invite.save?
# rel was created, move on
else
# something wrong in the rel, figure out what it was
end
Since you know you're always going to create that interested property, this looks like a good place to add a validation to your model to ensure that the property is always set on create.
I have two models, Draft and Pick. Draft creates an array of available Players in an instance variable named 'available_players'. This is done using the 'before_save' callback. The callback runs the instance method 'start' which in turn runs 'set_active_players'. I've tested all of this in my Draft_spec and I have no problems loading players and having them returned in the available_players array. All my draft specs pass.
The problem is that when I try to access the 'available_players' instance variable from Pick.rb, it returns nil. If I call 'draft.start' (the instance method that should run before Draft.rb saves), I can suddenly access the 'available_players' array... it's like the Draft object is not creating the available_players array even though I have the before_save method in place.
Here is the code that fails inside of Pick.rb:
def available_players_returns_nil
#draft_object.available_players
end
Here is the code that works inside of Pick.rb:
def available_players_working
#draft_object.start
#draft_object.available_players
end
I don't want to have to call start every time I call the method because available_players should not need to reload ALL Players. Please help me access available_players!
Links: failing Pick specs, Pick.rb
EDIT:
I should add that #draft_object is found using
#draft_object = Draft.find(self.draft_id)
For a start, this is wrong:
#draft_object = Draft.find(self.draft_id)
You have an association set up, so use it. You can simply use draft within your Pick object to access the Draft it belongs to. No need to assign it to an instance variable called #draft_object.
Same story with player.
Incidentally, your set_available_players method in Draft is just looping through all of the players and adding them to an instance variable. Why are you doing this? Why don't you simply grab the players directly if you need them in Pick? Like this:
#players = Player.all
Also ... I'm somewhat concerned that pretty much all of your tests are commented out. I hope that's not by design?
ruby_on_rails rails 4 assignment non-screen data to insert record
Rather than using screen values (e.g. simple_form_for #user_evaluation_result) to populate the columns to insert a row I need to calculate some of the values in controller.
For example if I have these statements in the controller
….
# which if I had simple_form_for user_evaluation_result would get populated by the screen
#user_evaluation_result = UserEvaluationResult.new(user_evaluation_result_params)
….
# standard stuff I use for screen derived updates
def user_evaluation_result_params
params.require(:user_evaluation_result).
permit(:evaluation_assumption_id,
:company_listing_id,
:target_share_price_dollars )
end
How do I assign values to :user_assumption_id etc so that insert works. I have tried all sorts of statements. Alternatively do I use another format instead of calling "def user_evaluation_result_params".
Thanks in advance - Pierre
I'm hoping I've interpreted the question properly...
First, to make sure we're on the same page... The code inside of your user_evaluation_result_params method is using Strong Parameters to create an ActionController::Parameters object for the purpose of protecting your model from unpermitted mass-assignments. So, in general, when you're creating or updating an ActiveRecord object from a form in a view template, you want to use Strong Parameters so that users can't manipulate your form to set attributes that you're not expecting.
That said, if you want to set attributes on an object you don't have to use mass assignment. Here is an example of using one-at-a-time assignment (the opposite of mass-assignment):
obj = MyObject.new
obj.attr_one = "One"
obj.attr_two = "Two"
obj.save
There is nothing wrong with this approach other than that it's kind of a lot of work for the general case. So mass-assignment just saves us from having to do this all the time. But it sounds like this one-at-a-time assignment is what you're wanting in this case. So try something like this:
def create
#user_evaluation_result = UserEvaluationResult.new
# assuming you have a UserAssumption object instance in `my_user_assumption`
#user_evaluation_result.user_assumption = my_user_assumption
#user_evaluation_result.some_other_attr = "some value"
#user_evaluation_result.save
end
Note, instead of setting #user_evaluation_result.user_assumption_id directly, as you asked about, it is preferred to set the actual object association as I did above. Try to keep associations outside of mass-assignment and use object relationships to build up your object graphs.
Or, if you have some attributes coming from a form you can mix and match the two approaches:
def create
#user_evaluation_result = UserEvaluationResult.new(user_evaluation_result_params)
# assuming you have a UserAssumption object instance in `my_user_assumption`
#user_evaluation_result.user_assumption = my_user_assumption
#user_evaluation_result.some_other_attr = params[:user_evaluation_result][:some_other_attr]
#user_evaluation_result.save
end
private
def user_evaluation_result_params
params.require(:user_evaluation_result)
.permit(:evaluation_assumption_id,
:company_listing_id,
:target_share_price_dollars)
end
I have a method that creates a new object and calls a service with that new object as a parameter, and returns the new object. I want to test in rspec that the method calls the service with the created object, but I don't know the created object ahead of time. Should I also stub the object creation?
def method_to_test
obj = Thing.new
SomeService.some_thing(obj)
end
I'd like to write:
SomeService.stub(:some_thing)
SomeService.should_receive(:some_thing).with(obj)
method_to_test
but I can't because I don't know obj until method_to_test returns...
Depending whether or not it's important to checkobj you can do:
SomeService.should_receive(:some_thing).with(an_instance_of(Thing))
method_to_test
or:
thing = double "thing"
Thing.should_receive(:new).and_return thing
SomeService.should_receive(:some_thing).with(thing)
method_to_test