This is an incredibly newbish question, but I can't seem to find the answer.
I'm building an app that utilizes external APIs heavily, and I'm fairly new to Rails, so it's still a little rough to get around. I can't, for the life of me, figure out how to accept user input and execute a function in my app without writing to a model.
For example, I just want to let a user type in a Twitter username and have it display on the page. I know how to make a form to cache the search in a model, but I can't figure out how to just... make a function happen on a page. I've been breaking my brains on this for several days now.
Please help? :/
You don't need a model to use Rails, but if you don't need ActiveRecord at all, you might benefit from a lighter framework like Sinatra. That doesn't answer your question, but it's worth thinking about if you really have no database requirement for your application.
It sounds like you're just trying to access non-resourceful user input, which is accessible in the controller via the params hash. So, assuming you have set up a valid route for the form action, you use your controller to extract GET or POST parameters.
For example:
# You define a non-resourceful route in routes.rb for your form action.
get 'twitternames/show'
# Form action directs user to GET the following route after filling in the form.
http://example.com/twitternames/show?user=foo
# The controller action extracts the data.
def show
#user = params[:user]
# render the view unless you tell rails to do something else
end
# show.html.erb
<%= #user %>
Creating the right route is the key. Once you've defined a route that can break a URL into the proper segments, the rest will fall into place.
Related
Quite new to rails/spree and am trying to create a pdf uploader where users can upload images that will then be sent to the company but when I try to send it I get an undefined local variable or method for 'spree_current_user'.
This is the line that gives the error. I know this would normally grab the id (I have used the same line in controllers) but I am not sure why it wouldn't work within the order mailer.
pdfs = Pdf.where(user_id: spree_current_user.id, created_at: Date.today-1.hour)
Basically I'm just wondering if anybody knows what else I could do? I tried to pass it through the controller as a session[] but this didn't work either.
If there are any other files that you might need to look at then please let me know. Would very much appreciate any help !
Thanks in advance.
You can't access the session or Controller helpers (which spree_current_user is one of). You must pass controller-level information to the objects (mailers) you want them in.
So the calling code for the uploader object must pass in the user id into the object where you want it. Since you didn't specify what object that is (exactly) I can't really answer out of context. But as a general rule session-level concepts (like the current user) belong to the controller, and if you want them elsewhere (outside of the controller) you need to pass them along with the call to the objects that are called from the controller.
If that's not possible, a first-order association (like adding user_id to the object in question) is also a good solution, depending on your domain model.
I have solved this issue if anyone else is needing it. What I did was pass the user id through a hidden field in the view:
hidden_field_tag 'current_user', spree_current_user.id
Then I added it in the controller
OrderMailer.send_to_client(..., ..., ..., params[:current_user]).deliver
I then changed my original pdf line to account for pdfs created in between certain times:
pdfs = Pdf.where(user_id: current_user, pdf_updated_at: Time.now-1.hour..Time.now)
As well as sending it through in this method.
def send_to_client( ..., ..., ..., current_user)
Hope this helps if anyone is experiencing a similar issue :).
I need some help with the authorization. So far I was trying to solve it with the internal rails authorization combined with devise.
I have a user who is posting a request. If this request is private only a group of "reader" can see and answer the request. (This is number one)
Then the user give a rating to the answer of the reader. This should be accesible only for the user which received the answer and the "reader" who gave an answer.
So far I was using the following to limit access to the hidden requests:
before_filter :require_reader!, only: [:open_requests]
But if the request is not hidden, than still only the reader should be able to answer the request (but all can see it). Here I do not know how to manage this. Any Ideas?
To continue... I could not manage to solve the second problem (that the rating is seen only be the one who was placing the request and the reader).
Any ideas here?
Is cancancan maybe an option?
Best
witali
What you're doing does not quite follow the 'admin' pattern that's commonly setup with tools like Railsbricks. The 'admin' permissions pattern is typically a whole set of actions/views that are available only to admins, so often the entire Controller, or family of controllers, have the :require_admin! filter applied before every single action and view. Very simple permissions logic, and it depends only on the user and view.
Instead, what you've got is views with permissions that depend on your object's state as well as the user's status and the view. So you're going to have to write your own filter to use instead of using 'require_reader!'.
For example, you might have a RequestsController, and you could add to it:
before_action :must_be_able_to_view_request, except: [:index, :new, :create]
Then define that filter in the controller:
private
def must_be_able_to_view_request
if !current_user.is_reader? && !#request.ispublic
head :forbidden
end
end
If you need to use the same filter in other Controllers, then you can define it in your ApplicationController.
I'm working on a project where users can upload videos through a simple form and additionally by FTP to a certain directory and then simply choose the file from the FTP directory instead of uploading it through the form.
I got the following, pretty standard setup for a videos_controller:
# routes.rb
resources :videos
# new.html.rb
form_for(#video) do |f|
...
end
The restful actions in the controller are all working and just standard behaviour. The upload works, that's not the problem. The problem is if I do the following:
# routes.rb
resources :videos do
member do
post :from_ftp
end
end
# new.html.rb
form_for(#video, :url => from_ftp_video_url) do |f|
...
end
I get the error: No route matches {:action=>"from_ftp", :controller=>"videos"}, because the generated route looks like this:
from_ftp_video POST /videos/:id/from_ftp(.:format) videos#from_ftp
which seems right, since it's a member route. But I don't need the :id part of the URL, since I'm creating a new Video object, not through a form but simply by using the file from the FTP directory... So it basically is another create action, that's why I would like to do it as a POST request...
So how do I tackle this the best way?
Although the selected answer is correct for Vapire's situation, it doesn't necessarily answer the title question. If you came here looking for how to get member actions without an ID because you don't need an ID, the answer is a little different.
Say you implemented authentication that sets current_user. You let users edit their own profile only. In that case users/:id/edit doesn't make sense because :id is dictated by the current_user method. In this case /users/edit makes more sense.
You can change your routes.rb file to create member actions without an id in the path.
...instead of this...
resources :user
...use this (note the plurality of resource)...
resource :user
The way to understand member and collection routes is this:
Member routes do something to an object that you have.
Collection routes do something to the set of all objects.
So when we consider what the create route would be, it's a collection route, because it's adding a new object to the collection!
So your from_ftp method should also be a collection route, because it's adding to the collection.
Also, you might want to consider if you can accommodate the FTP functionality within your existing create method - it might be neater.
NOTE: I have read Routing From the Inside Out AND the Engine Yard blog post on routing.
I'm building a fantasy sports league, I have a League model that supports the seven basic restful operations, and they all work fine.
I've added the following my routes.rb
resources :leagues do
member do
get :invite
post :sendem
end
Later in the file I have a resources :leagues for the basic actions
and when I rake routes I can see:
invite_league GET /leagues/:id/invite(.:format) {:action=>"invite", :controller=>"leagues"}
sendem_league POST /leagues/:id/sendem(.:format) {:action=>"sendem", :controller=>"leagues"}
which is what I would expect. I have two functions in the League controller: "invite" which creates the form for collecting email addresses, and "sendem" which invokes a mailer to actually send the invitations.
The get for /league/:id/invite does indeed produce the form.
The form tag I am using looks like:
<%= form_tag(sendem_league_path, :method => "post") do %>
and yet the HTML that is rendered looks like:
<form accept-charset="UTF-8" action="/leagues/1" class="edit_league" id="edit_league_1" method="post">
And hence on submit generates a PUT which is completely wrong. (It should post to the sendem function.) My change to the routes file appears above the generic resources :leagues line, so it should have a higher priority.
I'm sure there is something dead-simple that I missed but I'm out of ideas. (And hair).
You should not use form_tag for manipulating resources.
You should use form_for.
Check out form helper guide - section 2 "Dealing with Model Objects". It takes care of deducing whether to use POST or PUT for a model object. For example, if your model object is new, it will use post on "resources"'s URL. if it is already existing database entity, it will use PUT to that "resource"'s URL.
ARGH some form handling error code at the top (form for #league) created a second form on the page for editing.... (left out of code snippets above for brevity). Original code seems to work as expected with that other code commented out. Thanks to vladdruzh for convincing me I was on the right track and to Salil for making me think to read the rendered HTML top to bottom.
I trying to prevent url hacking, I passing an id to the url that the forms need, it works fine but if the user changes that value on the url it will send values to the wrong table.
<%= link_to '+ New Event',
{:controller =>'events', :action =>
'new', :company_id => company.id} %>
On the php world I used to encrypt that id ...how can I do this on rails3 or is there a better way ??
needless to say I sort of new to rails and I know a little bit of php
any help or suggestions will be greatly appreciated.
Even though this is an older question, it's a very worthwhile question. It is absolutely worthwhile to conceal the ID in the URL for, among other things, prevention of information disclosure.
For example, an application has a robust security model allowing users to only view resources to which they have rights. However, why should a user be able to look at the value of the ID in the URL and use it to deduce how many resources there are or, as the original questioner suggests, start trying to poke around with forced browsing.
The solution to this in rails turns out to be pretty simple. What I find works best is overriding to_param in the models, usually via a module in the lib directory and a before_filter in the application controller that decrypts the IDs.
For a walkthrough, have a look at this: http://www.youtube.com/watch?v=UW_s9ejrCsI
Rather than trying to encrypt or hide your company.id value, ask yourself what exactly it is that you want to prevent users from doing.
If you just want to prevent users from creating events associated with non-existant companies (by setting the id to a really high value for instance), then a simple
validates_presence_of :company
On the Event model would be fine.
If you only want users to be able to create events associated with companies that they work for, or have access for in some way, then you should create custom validations to verify that.
F