Place to put parameter object in rails - ruby-on-rails

I'm new Rails guy and I have problem with the structure of Rails.
My application structure like this
- app
- controllers
-- orders_controller.rb
- services
-- get_customer.rb
OrdersController receive create order request and return new order. Because Order belongs to Customer. So I create a service name GetCustomer in order to find or create new customer if not exists.
However, the action method in GetCustomer service receive a long parameters. So I need to extract this parameter into another Object. But I don't know where place should I put it in ?
Any advice is graceful for me ! Thanks

Hi Your questions is not specific though here is my answer based on what you asked. In your service you can simply set an instance variable to the specific param that you want. example below:
def initialize(params)
#phone= params[:phone]
#something = params[:somthing]
#email = params[:email]
end
You would have to list specific code if you would like a more specific answer.

Related

creating dynamic variable for ruby objects in rails project

I am fairly new to rails and am just getting into using cool gems and APIs. I have been made aware that this community values the contents of questions and answers, or it is expected that they are constructed in a specific way. The short way to ask my question and the long way are provided. Please let me know which is preferred here! It is a real question though!
SHORT VERSION
I have a users_controller and User object with a username attribute in a rails app. How do I create global variables for these users that is dynamically based on their username? Example: I want with my user (id = 1, first_name = "Rob", username = "rocky") to be callable as #rocky. So what would go below in my Users_controller that is based on the first code line below working for me in terminal:
#rocky = User.find_by_username("rocky")
WHATGOESHERE = User.find_by_username(params[:username]}
or should I be using this in some shape or form in place of params[:username]
#"#{user.username}"
Below is the longer version of my question. It is more detailed and follows more closely how I approached the issue. The first one... that I wrote second, is more concise but that's not always what people want... please let me know which is preferred on this site. Thanks!!
LONG VERSION
I need some clarity on a few things. I am using a gem called "has_friendship" to create friendships between my users (link to gem- https://github.com/sungwoncho/has_friendship ).
First, this is the documentations example of how to request a friendship, starting with the creation of the users.
#mac = User.create(name: "Mac")
#dee = User.create(name: "Dee")
# #mac sends a friend request to #dee
#mac.friend_request(#dee)
This is where I first became confused. My users don't have a "name" field. But that's ok. I managed to figure out that I just need to assign my created users global variables as they do... since my users will be interacting with each other behind their "username" attribute. So first question, How do I assign a dynamic variable name to each user? In the documentation, they are hard-coding in the names "Mac" and "Dee." I need to have this global variable be created upon the creation of the object.. So my plan is to do this in the controller. Here I am already defining #users and #user in users#show
#users = User.all
#user = User.includes(:wallet).find_by_id(params[:id])
So my thought process is that the left side of the equation should be the name of what you're naming and the right side is what that name is referring to. So for the right side, I'd think to put
User.find_by_username(params[:username])
as when in the terminal, if I replace the content in parenthesis with an actual username in quotes, it brings up that user's info. So how do I write the left side. I would think the left side is something like this:
#"#{params[:username]}"
So in full I currently have the following in my users_controller to assign global variables to my users based on their username atttribute...
#"#{params[:username]}" = User.find_by_username(params[:username])
This, especially the left side, does not look at all right to me. So I've looked around on google a bunch and the only other thing I can find that looks like the right way to do this is by using "instance_variable_set" but everything I've looked at doesn't make total sense for my situation... (as usual.. ha)
Ok what I get to know from your question is you want to use friend_request method to associate two users.
For this, you don't need to assign them to any variables. You can directly do this by something like this -
Suppose there are two user's
id=1 first_name='Rocky' username='rocky'
id=2 first_name='Nimish' username='nimish'
User.find_by(username: 'rocky').friend_request(User.find_by(username: 'nimish'))
OR
User.find_by_username('rocky').friend_request(User.find_by_username( 'nimish'))
Also, If you want to assign them to instance variable then it is not necessary to create an instance variable corresponding to the username value
You can simply assign them to #user and #requested_user and then
#user.friend_request(#requested_user)

Different update / edit methods available to different users

I have a model Post, which is submitted and graded by different Users. The submitter and grader are identified by submitter_id and grader_id in Post model. Note that an user is both a submitter himself and a grader to others.
I want to make sure that the submitter can only edit the content of the Post but not the grade. Likewise, the grader can only edit the grade but not the content.
Is multiple edit methods the way to go? How should I accomplish this otherwise?
You can have a role column in your users table, and the role can be either submitter or grader. Not sure what you are using for authentication, but in case you are using devise, you can access the currently logged in user with current_user helper (in case you are using something else, figure this part out, or add a new helper).
Now in your update method, you can do something like this:
# Controller
# scope post to current user, so that a user cannot edit someone else's post. A crude way to achieve this is post = Post.find(params[:id])
post = current_user.posts.find(params[:id])
post.content = params[:content] if post.submitter?(current_user.id)
post.grade = params[:grade] if post.grader?(current_user.id)
post.save!
# Model - Post.rb
def submitter?(user_id)
self.submitter_id == user_id
end
def grader?(user_id)
self.grader_id == user_id
end
The advantage of keeping those methods in the model is that in case you permission logic changes (who is submitter, or a grader), you need to change it at a single location. DRY.
You can modify the above approach to show error messages, and do other similar stuff. In case you are looking for more granular authorization control, you can look into cancan gem:
https://github.com/ryanb/cancan
Your post model should only be concerned with persisting data. Better to use plain old ruby objects to encapsulate the higher order behavior of grading and submitting. Consider using service objects or form objects.
Each service or form object can then include ActiveModel::Model(rails > v4) to get its own validations.
See more about service and form objects here: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
If you only have one submit action and one grade action, its probably ok to keep in one controller. But if you start having multiple actions that are related to submitted, and multiple actions that are related to grading, this sounds like they would make great resources controllers on their own.

What's the absolute path to current request object in Rails environment?

I'm searching for the current request of class Rack::Request to find the params. Suppose I've spawned a debugger in my model, I don't want to send a new request, but still find my params.
I couldn't find any class attributes, that would store current request, which is reasonable.
I don't know how to find any instances of ApplicationController or Rack::Server, which might contain the info.
Also, peaking into the log is considered too much effort, so I'd like the effort to be concentrated on finding the request object, not telling me to grep/search through log.
In hopes of being able to be lazy,
Love Dzhon.
It's possible I'm misunderstanding your question, but from within a controller you can simply access a request object to get its details, and params to get the params.
ItemController
def show
#page_variable = request.inspect + params.inspect
end
end
If you want to make the request object available to your models you can create a class accessor and store it at the beginning of any action (via a before_filter in the application controller) for example. More details why here.

Ruby on rails, pass an argument from one action to another

I have two actions in my controller:search, show_db.
say, they look like this:
def search
#uploads=current_user.uploads
end
def show_db
end
I need to pass arguments (#uploads) from search-action to show_db-action. (I know I could write #uploads=current_user.uploads in show_db, but I cannot, it is much more complex.)
smt like this:
def search
#uploads=current_user.uploads
show_db(#uploads)
end
def show_db(list)
blablabla
end
Is it possible to do?=)
Many thanks in advance.
If you want to pass the result of one method to another it's pretty simple in Ruby, your second code block should work, you just need to use the list variable from the parameter in your method
def show_db(list)
x = list
list.do_somethings
etc
end
Create a third method that knows how to create #uploads, use it from both actions.
Also, if in your index action you want to render show_db with #uploads variable, you can do this:
def search
#uploads=current_user.uploads
if something
return show_db(#uploads)
end
end
def show_db(list)
blah
render 'show_db'
end
But in this case, show_db is just a method, not a controller action.
You probably want to use a variable across actions. You should know that each time you make a request from browser, you are creating a new instance of controller. Hence, your variables would not work as they should because you will actually be trying to access an instance variable across instances. An impossible task.
I suggest using sessions to store information across multiple requests.
Google up how to use sessions.

ActionMailer- access Mail::Message content, or manually initialize view in controller?

I've got a form where an internal user can request that informational materials be sent to a client. When the form is submitted, it sends an email to the person in charge of physically mailing the materials to the client.
Now, I want to capture the content of the email so I can add a note to the client's show page, and I'm unsure how to go about it.
One option I've looked at is to use an after_filter in the MaterialsRequestMailer, but calling message.body returns a large string with way more text than I need and I want to avoid adding a bunch of parsing logic to get the message content.
Basically, I want what is generated by the views/materials_request_mailer/send_request_notification.text.erb template. I've looked through http://www.rubydoc.info/github/mikel/mail/Mail/Message and can't find a method to return just the rendered template content. Is there a way to do that?
If not, is there a way to manually initialize a View in the controller, where I already have the instance variables I'm passing to the mailer? That doesn't seem to be an ideal solution, because I'm using DelayedJob, and the code for adding the note would be run before the email is actually sent. Also, due to DelayedJob, it appears that I can't directly access the mail object from within the controller (if I do mail = MaterialsRequestMailer.delay.send_request_notification(...) it assigns an instance of Delayed::Backend::ActiveRecord::Job to mail).
Found a solution that works- message.text_part.body.raw_source is what I was looking for. (credit to this answer: https://stackoverflow.com/a/15257098/2599738)
class MaterialsRequestMailer < ActionMailer::Base
include AbstractController::Callbacks
after_filter :add_note_to_client
def send_request_notification(client, ...)
#client = client
...
end
def add_note_to_client
mail_text = message.text_part.body.raw_source
#client.add_account_note(mail_text)
end
end

Resources